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