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 com.intellij.psi.tree.IElementType;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
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.psi.psiUtil.PsiUtilPackage;
032    import org.jetbrains.kotlin.types.JetType;
033    import org.jetbrains.kotlin.types.SubstitutionUtils;
034    import org.jetbrains.kotlin.types.TypeConstructor;
035    import org.jetbrains.kotlin.types.TypeProjection;
036    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
037    
038    import javax.inject.Inject;
039    import java.util.*;
040    
041    import static org.jetbrains.kotlin.diagnostics.Errors.*;
042    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE;
043    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_PARAMETER;
044    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers;
045    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers;
046    
047    public class DeclarationsChecker {
048        private BindingTrace trace;
049        private ModifiersChecker modifiersChecker;
050        private DescriptorResolver descriptorResolver;
051    
052        @Inject
053        public void setTrace(@NotNull BindingTrace trace) {
054            this.trace = trace;
055        }
056    
057        @Inject
058        public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
059            this.descriptorResolver = descriptorResolver;
060        }
061    
062        @Inject
063        public void setModifiersChecker(@NotNull ModifiersChecker modifiersChecker) {
064            this.modifiersChecker = modifiersChecker;
065        }
066    
067        public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
068            for (JetFile file : bodiesResolveContext.getFiles()) {
069                checkModifiersAndAnnotationsInPackageDirective(file);
070            }
071    
072            Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses();
073            for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) {
074                JetClassOrObject classOrObject = entry.getKey();
075                ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
076    
077                checkSupertypesForConsistency(classDescriptor);
078                checkTypesInClassHeader(classOrObject);
079    
080                if (classOrObject instanceof JetClass) {
081                    JetClass jetClass = (JetClass) classOrObject;
082                    checkClass(bodiesResolveContext, jetClass, classDescriptor);
083                    descriptorResolver.checkNamesInConstraints(
084                            jetClass, classDescriptor, classDescriptor.getScopeForClassHeaderResolution(), trace);
085                }
086                else if (classOrObject instanceof JetObjectDeclaration) {
087                    checkObject((JetObjectDeclaration) classOrObject, classDescriptor);
088                }
089    
090                modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
091            }
092    
093            Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
094            for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
095                JetNamedFunction function = entry.getKey();
096                SimpleFunctionDescriptor functionDescriptor = entry.getValue();
097    
098                checkFunction(function, functionDescriptor);
099                modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor);
100            }
101    
102            Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties();
103            for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
104                JetProperty property = entry.getKey();
105                PropertyDescriptor propertyDescriptor = entry.getValue();
106    
107                checkProperty(property, propertyDescriptor);
108                modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
109            }
110    
111            for (Map.Entry<JetSecondaryConstructor, ConstructorDescriptor> entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) {
112                ConstructorDescriptor constructorDescriptor = entry.getValue();
113                JetSecondaryConstructor declaration = entry.getKey();
114                checkConstructorDeclaration(constructorDescriptor, declaration);
115            }
116    
117        }
118    
119        private void checkConstructorDeclaration(ConstructorDescriptor constructorDescriptor, JetDeclaration declaration) {
120            modifiersChecker.reportIllegalModalityModifiers(declaration);
121            reportErrorIfHasIllegalModifier(declaration);
122            modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor);
123        }
124    
125        private void reportErrorIfHasIllegalModifier(JetModifierListOwner declaration) {
126            if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) {
127                trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration));
128            }
129            if (declaration.hasModifier(JetTokens.ANNOTATION_KEYWORD)) {
130                trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration));
131            }
132        }
133    
134        private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) {
135            JetPackageDirective packageDirective = file.getPackageDirective();
136            if (packageDirective == null) return;
137    
138            JetModifierList modifierList = packageDirective.getModifierList();
139            if (modifierList == null) return;
140    
141            for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
142                JetConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression();
143                if (calleeExpression != null) {
144                    JetReferenceExpression reference = calleeExpression.getConstructorReferenceExpression();
145                    if (reference != null) {
146                        trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
147                    }
148                }
149            }
150    
151            ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace);
152        }
153    
154        private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) {
155            for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
156                checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
157            }
158    
159            if (!(classOrObject instanceof JetClass)) return;
160            JetClass jetClass = (JetClass) classOrObject;
161    
162            for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
163                checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
164                checkFinalUpperBounds(jetTypeParameter.getExtendsBound());
165            }
166    
167            for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
168                checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
169                checkFinalUpperBounds(constraint.getBoundTypeReference());
170            }
171        }
172    
173        private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) {
174            if (typeReference != null) {
175                JetType type = trace.getBindingContext().get(TYPE, typeReference);
176                if (type != null) {
177                    DescriptorResolver.checkBounds(typeReference, type, trace);
178                }
179            }
180        }
181    
182        private void checkFinalUpperBounds(@Nullable JetTypeReference typeReference) {
183            if (typeReference != null) {
184                JetType type = trace.getBindingContext().get(TYPE, typeReference);
185                if (type != null) {
186                    DescriptorResolver.checkUpperBoundType(typeReference, type, trace);
187                }
188            }
189        }
190    
191        private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) {
192            Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
193                    .buildDeepSubstitutionMultimap(classDescriptor.getDefaultType());
194            for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
195                Collection<TypeProjection> projections = entry.getValue();
196                if (projections.size() > 1) {
197                    TypeConstructor typeConstructor = entry.getKey();
198                    DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
199                    assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
200                    TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
201    
202                    // Immediate arguments of supertypes cannot be projected
203                    Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
204                    for (TypeProjection projection : projections) {
205                        conflictingTypes.add(projection.getType());
206                    }
207                    removeDuplicateTypes(conflictingTypes);
208                    if (conflictingTypes.size() > 1) {
209                        DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
210                        assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
211                        JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor);
212                        assert psiElement != null;
213                        JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
214                        assert delegationSpecifierList != null;
215                        //                        trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
216                        trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
217                                             .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
218                                                 conflictingTypes));
219                    }
220                }
221            }
222        }
223    
224        private static void removeDuplicateTypes(Set<JetType> conflictingTypes) {
225            for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
226                JetType type = iterator.next();
227                for (JetType otherType : conflictingTypes) {
228                    boolean subtypeOf = JetTypeChecker.DEFAULT.equalTypes(type, otherType);
229                    if (type != otherType && subtypeOf) {
230                        iterator.remove();
231                        break;
232                    }
233                }
234            }
235        }
236        private void checkObject(JetObjectDeclaration declaration, ClassDescriptor classDescriptor) {
237            AnnotationResolver.reportDeprecatedAnnotationSyntax(declaration.getAnnotations(), trace);
238            reportErrorIfHasIllegalModifier(declaration);
239            if  (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) {
240                trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor));
241            }
242        }
243    
244        private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
245            AnnotationResolver.reportDeprecatedAnnotationSyntax(aClass.getAnnotations(), trace);
246            checkOpenMembers(classDescriptor);
247            checkPrimaryConstructor(aClass, classDescriptor);
248            checkTypeParameters(aClass);
249    
250            if (aClass.isInterface()) {
251                ASTNode traitKeyword = aClass.getNode().findChildByType(JetTokens.TRAIT_KEYWORD);
252                if (traitKeyword != null) {
253                    trace.report(Errors.DEPRECATED_TRAIT_KEYWORD.on(traitKeyword.getPsi()));
254                }
255    
256                checkTraitModifiers(aClass);
257                checkConstructorInTrait(aClass);
258            }
259            else if (aClass.isAnnotation()) {
260                checkAnnotationClassWithBody(aClass);
261                checkValOnAnnotationParameter(aClass);
262            }
263            else if (aClass.isEnum()) {
264                checkEnumModifiers(aClass);
265                if (aClass.isLocal()) {
266                    trace.report(LOCAL_ENUM_NOT_ALLOWED.on(aClass, classDescriptor));
267                }
268            }
269            else if (aClass instanceof JetEnumEntry) {
270                checkEnumEntry((JetEnumEntry) aClass, classDescriptor);
271            }
272        }
273    
274        private void checkPrimaryConstructor(JetClass aClass, ClassDescriptor classDescriptor) {
275            ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
276            JetPrimaryConstructor declaration = aClass.getPrimaryConstructor();
277            if (primaryConstructor == null || declaration == null) return;
278    
279            for (JetParameter parameter : declaration.getValueParameters()) {
280                PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
281                if (propertyDescriptor != null) {
282                    modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor);
283                }
284            }
285    
286            if (declaration.getModifierList() != null && !declaration.hasConstructorKeyword()) {
287                trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList()));
288            }
289    
290            checkConstructorDeclaration(primaryConstructor, declaration);
291        }
292    
293        private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
294            // TODO: Support annotation for type parameters
295            for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
296                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
297    
298                TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
299                if (typeParameter != null) {
300                    DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
301                }
302            }
303        }
304    
305        private void checkConstructorInTrait(JetClass klass) {
306            JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
307            if (primaryConstructorParameterList != null) {
308                trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructorParameterList));
309            }
310        }
311    
312        private void checkTraitModifiers(JetClass aClass) {
313            reportErrorIfHasIllegalModifier(aClass);
314            JetModifierList modifierList = aClass.getModifierList();
315            if (modifierList == null) return;
316            if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) {
317                trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(aClass));
318            }
319            if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
320                trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass));
321            }
322            if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) {
323                trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass));
324            }
325        }
326    
327        private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) {
328            if (classOrObject.getBody() != null) {
329                trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
330            }
331        }
332    
333        private void checkValOnAnnotationParameter(JetClass aClass) {
334            for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
335                if (!parameter.hasValOrVarNode()) {
336                    trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
337                }
338            }
339        }
340    
341        private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
342            if (classCanHaveOpenMembers(classDescriptor)) return;
343    
344            for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
345                if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
346                JetNamedDeclaration member = (JetNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor);
347                if (member != null && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
348                    trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
349                }
350            }
351        }
352    
353        private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
354            reportErrorIfHasIllegalModifier(property);
355            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
356            if (containingDeclaration instanceof ClassDescriptor) {
357                checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
358            }
359            else {
360                modifiersChecker.reportIllegalModalityModifiers(property);
361            }
362            checkPropertyInitializer(property, propertyDescriptor);
363            checkAccessors(property, propertyDescriptor);
364            checkDeclaredTypeInPublicMember(property, propertyDescriptor);
365        }
366    
367        private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) {
368            boolean hasDeferredType;
369            if (member instanceof JetProperty) {
370                hasDeferredType = ((JetProperty) member).getTypeReference() == null && DescriptorResolver.hasBody((JetProperty) member);
371            }
372            else {
373                assert member instanceof JetFunction;
374                JetFunction function = (JetFunction) member;
375                hasDeferredType = function.getTypeReference() == null && function.hasBody() && !function.hasBlockBody();
376            }
377            if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) {
378                trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member));
379            }
380        }
381    
382        private void checkPropertyAbstractness(
383                @NotNull JetProperty property,
384                @NotNull PropertyDescriptor propertyDescriptor,
385                @NotNull ClassDescriptor classDescriptor
386        ) {
387            JetPropertyAccessor getter = property.getGetter();
388            JetPropertyAccessor setter = property.getSetter();
389            JetModifierList modifierList = property.getModifierList();
390            ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
391    
392            if (abstractNode != null) { //has abstract modifier
393                if (!classCanHaveAbstractMembers(classDescriptor)) {
394                    String name = property.getName();
395                    trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
396                    return;
397                }
398                if (classDescriptor.getKind() == ClassKind.INTERFACE) {
399                    trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property));
400                }
401            }
402    
403            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
404                JetExpression initializer = property.getInitializer();
405                if (initializer != null) {
406                    trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
407                }
408                JetPropertyDelegate delegate = property.getDelegate();
409                if (delegate != null) {
410                    trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
411                }
412                if (getter != null && getter.hasBody()) {
413                    trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
414                }
415                if (setter != null && setter.hasBody()) {
416                    trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter));
417                }
418            }
419        }
420    
421        private void checkPropertyInitializer(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
422            JetPropertyAccessor getter = property.getGetter();
423            JetPropertyAccessor setter = property.getSetter();
424            boolean hasAccessorImplementation = (getter != null && getter.hasBody()) ||
425                                                (setter != null && setter.hasBody());
426    
427            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
428                if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null) {
429                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
430                }
431                return;
432            }
433            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
434            boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.INTERFACE;
435            JetExpression initializer = property.getInitializer();
436            JetPropertyDelegate delegate = property.getDelegate();
437            boolean backingFieldRequired =
438                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
439    
440            if (inTrait && backingFieldRequired && hasAccessorImplementation) {
441                trace.report(BACKING_FIELD_IN_TRAIT.on(property));
442            }
443    
444            if (initializer == null && delegate == null) {
445                boolean error = false;
446                if (backingFieldRequired && !inTrait &&
447                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, propertyDescriptor))) {
448                    if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
449                        error = true;
450                        trace.report(MUST_BE_INITIALIZED.on(property));
451                    }
452                    else {
453                        error = true;
454                        trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
455                    }
456                }
457                if (!error && property.getTypeReference() == null) {
458                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
459                }
460                if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) {
461                    trace.report(FINAL_PROPERTY_IN_TRAIT.on(property));
462                }
463                return;
464            }
465    
466            if (inTrait) {
467                if (delegate != null) {
468                    trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate));
469                }
470                else {
471                    trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
472                }
473            }
474            else if (delegate == null) {
475                if (!backingFieldRequired) {
476                    trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
477                }
478                else if (property.getReceiverTypeReference() != null) {
479                    trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer));
480                }
481            }
482        }
483    
484        protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
485            reportErrorIfHasIllegalModifier(function);
486            DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
487            boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
488            checkDeclaredTypeInPublicMember(function, functionDescriptor);
489            if (containingDescriptor instanceof ClassDescriptor) {
490                ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
491                boolean inTrait = classDescriptor.getKind() == ClassKind.INTERFACE;
492                if (hasAbstractModifier && !classCanHaveAbstractMembers(classDescriptor)) {
493                    trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
494                }
495                if (hasAbstractModifier && inTrait) {
496                    trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
497                }
498                boolean hasBody = function.hasBody();
499                if (hasBody && hasAbstractModifier) {
500                    trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
501                }
502                if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
503                    trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
504                }
505                if (!hasBody && !hasAbstractModifier && !inTrait) {
506                    trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
507                }
508                return;
509            }
510            modifiersChecker.reportIllegalModalityModifiers(function);
511            if (!function.hasBody() && !hasAbstractModifier) {
512                trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
513            }
514        }
515    
516        private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
517            for (JetPropertyAccessor accessor : property.getAccessors()) {
518                PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
519                assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText();
520                modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor);
521                modifiersChecker.reportIllegalModalityModifiers(accessor);
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, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(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 (ASTNode node : nodes.values()) {
532                        trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi()));
533                    }
534                }
535                else {
536                    for (ASTNode node : nodes.values()) {
537                        trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi()));
538                    }
539                }
540            }
541        }
542    
543        private void checkEnumModifiers(JetClass aClass) {
544            if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) {
545                trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass));
546            }
547            if (aClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
548                trace.report(ABSTRACT_MODIFIER_IN_ENUM.on(aClass));
549            }
550        }
551    
552        // Temporary
553        // Returns true if deprecated constructor is in use, like
554        // ENTRY: Enum(arguments) instead of
555        // ENTRY(arguments)
556        public static boolean enumEntryUsesDeprecatedSuperConstructor(@NotNull JetEnumEntry enumEntry) {
557            JetInitializerList initializerList = enumEntry.getInitializerList();
558            if (initializerList == null) return false;
559            JetTypeReference typeReference = initializerList.getInitializers().get(0).getTypeReference();
560            if (typeReference == null) return false;
561            JetUserType userType = (JetUserType) typeReference.getTypeElement();
562            if (userType == null || userType.getReferenceExpression() instanceof JetEnumEntrySuperclassReferenceExpression) return false;
563            return true;
564        }
565    
566        // Temporary
567        // Returns comma if it's an enum entry without following comma (entry is not last in enum),
568        // or semicolon if it's an enum entry without following semicolon, may be after comma (entry is last in enum),
569        // or empty string if an enum entry has the necessary following delimiter
570        @NotNull
571        private static String enumEntryExpectedDelimiter(@NotNull JetEnumEntry enumEntry) {
572            PsiElement next = enumEntry.getNextSibling();
573            while (next != null) {
574                if (next instanceof JetDeclaration) break;
575                next = next.getNextSibling();
576            }
577            JetDeclaration nextDeclaration = (JetDeclaration) next;
578            next = PsiUtilPackage.getNextSiblingIgnoringWhitespaceAndComments(enumEntry);
579            IElementType nextType = next != null ? next.getNode().getElementType() : null;
580            if (nextDeclaration instanceof JetEnumEntry) {
581                // Not last
582                return nextType != JetTokens.COMMA ? "," : "";
583            }
584            else {
585                // Last: after it we can have semicolon, just closing brace, or comma followed by semicolon / closing brace
586                if (nextType == JetTokens.COMMA) {
587                    next = PsiUtilPackage.getNextSiblingIgnoringWhitespaceAndComments(next);
588                    nextType = next != null ? next.getNode().getElementType() : null;
589                }
590                return nextType != JetTokens.SEMICOLON && nextType != JetTokens.RBRACE ? ";" : "";
591            }
592        }
593    
594        public static boolean enumEntryUsesDeprecatedOrNoDelimiter(@NotNull JetEnumEntry enumEntry) {
595            return !enumEntryExpectedDelimiter(enumEntry).isEmpty();
596        }
597    
598        static public boolean enumEntryAfterEnumMember(@NotNull JetEnumEntry enumEntry) {
599            PsiElement previous = enumEntry.getPrevSibling();
600            while (previous != null) {
601                if (previous instanceof JetEnumEntry) return false;
602                if (previous instanceof JetDeclaration) return true;
603                previous = previous.getPrevSibling();
604            }
605            return false;
606        }
607    
608        private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
609            DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
610            assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor;
611            ClassDescriptor enumClass = (ClassDescriptor) declaration;
612    
613            if (enumEntryUsesDeprecatedSuperConstructor(enumEntry)) {
614                trace.report(Errors.ENUM_ENTRY_USES_DEPRECATED_SUPER_CONSTRUCTOR.on(enumEntry, classDescriptor));
615            }
616            String neededDelimiter = enumEntryExpectedDelimiter(enumEntry);
617            if (!neededDelimiter.isEmpty()) {
618                trace.report(Errors.ENUM_ENTRY_USES_DEPRECATED_OR_NO_DELIMITER.on(enumEntry, classDescriptor, neededDelimiter));
619            }
620            if (enumEntryAfterEnumMember(enumEntry)) {
621                trace.report(Errors.ENUM_ENTRY_AFTER_ENUM_MEMBER.on(enumEntry, classDescriptor));
622            }
623    
624            List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers();
625            ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor();
626            if ((constructor == null || !constructor.getValueParameters().isEmpty()) && delegationSpecifiers.isEmpty()) {
627                trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass));
628            }
629    
630            for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
631                JetTypeReference typeReference = delegationSpecifier.getTypeReference();
632                if (typeReference != null) {
633                    JetType type = trace.getBindingContext().get(TYPE, typeReference);
634                    if (type != null) {
635                        JetType enumType = enumClass.getDefaultType();
636                        if (!type.getConstructor().equals(enumType.getConstructor())) {
637                            trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass));
638                        }
639                    }
640                }
641            }
642        }
643    }