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.ImmutableSet;
020    import com.google.common.collect.Multimap;
021    import com.google.common.collect.Sets;
022    import com.intellij.psi.PsiElement;
023    import kotlin.jvm.functions.Function1;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
027    import org.jetbrains.kotlin.descriptors.*;
028    import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
029    import org.jetbrains.kotlin.diagnostics.Errors;
030    import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
031    import org.jetbrains.kotlin.lexer.KtTokens;
032    import org.jetbrains.kotlin.psi.*;
033    import org.jetbrains.kotlin.types.*;
034    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
035    import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
036    
037    import java.util.*;
038    
039    import static org.jetbrains.kotlin.diagnostics.Errors.*;
040    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE;
041    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_PARAMETER;
042    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers;
043    import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers;
044    
045    public class DeclarationsChecker {
046        @NotNull private final BindingTrace trace;
047        @NotNull private final ModifiersChecker.ModifiersCheckingProcedure modifiersChecker;
048        @NotNull private final DescriptorResolver descriptorResolver;
049        @NotNull private final AnnotationChecker annotationChecker;
050        @NotNull private final IdentifierChecker identifierChecker;
051    
052        public DeclarationsChecker(
053                @NotNull DescriptorResolver descriptorResolver,
054                @NotNull ModifiersChecker modifiersChecker,
055                @NotNull AnnotationChecker annotationChecker,
056                @NotNull IdentifierChecker identifierChecker,
057                @NotNull BindingTrace trace
058        ) {
059            this.descriptorResolver = descriptorResolver;
060            this.modifiersChecker = modifiersChecker.withTrace(trace);
061            this.annotationChecker = annotationChecker;
062            this.identifierChecker = identifierChecker;
063            this.trace = trace;
064        }
065    
066        public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
067            for (KtFile file : bodiesResolveContext.getFiles()) {
068                checkModifiersAndAnnotationsInPackageDirective(file);
069                annotationChecker.check(file, trace, null);
070            }
071    
072            Map<KtClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses();
073            for (Map.Entry<KtClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) {
074                KtClassOrObject classOrObject = entry.getKey();
075                ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
076    
077                checkSupertypesForConsistency(classOrObject, classDescriptor);
078                checkTypesInClassHeader(classOrObject);
079    
080                if (classOrObject instanceof KtClass) {
081                    KtClass ktClass = (KtClass) classOrObject;
082                    checkClass(bodiesResolveContext, ktClass, classDescriptor);
083                    descriptorResolver.checkNamesInConstraints(
084                            ktClass, classDescriptor, classDescriptor.getScopeForClassHeaderResolution(), trace);
085                }
086                else if (classOrObject instanceof KtObjectDeclaration) {
087                    checkObject((KtObjectDeclaration) classOrObject, classDescriptor);
088                }
089    
090                checkPrimaryConstructor(classOrObject, classDescriptor);
091    
092                modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
093                identifierChecker.checkDeclaration(classOrObject, trace);
094                checkClassExposedType(classOrObject, classDescriptor);
095            }
096    
097            Map<KtNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
098            for (Map.Entry<KtNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
099                KtNamedFunction function = entry.getKey();
100                SimpleFunctionDescriptor functionDescriptor = entry.getValue();
101    
102                checkFunction(function, functionDescriptor);
103                modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor);
104                identifierChecker.checkDeclaration(function, trace);
105            }
106    
107            Map<KtProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties();
108            for (Map.Entry<KtProperty, PropertyDescriptor> entry : properties.entrySet()) {
109                KtProperty property = entry.getKey();
110                PropertyDescriptor propertyDescriptor = entry.getValue();
111    
112                checkProperty(property, propertyDescriptor);
113                modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
114                identifierChecker.checkDeclaration(property, trace);
115            }
116    
117            for (Map.Entry<KtSecondaryConstructor, ConstructorDescriptor> entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) {
118                ConstructorDescriptor constructorDescriptor = entry.getValue();
119                KtSecondaryConstructor declaration = entry.getKey();
120                checkConstructorDeclaration(constructorDescriptor, declaration);
121                checkFunctionExposedType(declaration, constructorDescriptor);
122            }
123        }
124    
125        private void checkConstructorDeclaration(ConstructorDescriptor constructorDescriptor, KtDeclaration declaration) {
126            modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor);
127            identifierChecker.checkDeclaration(declaration, trace);
128        }
129    
130        private void checkModifiersAndAnnotationsInPackageDirective(KtFile file) {
131            KtPackageDirective packageDirective = file.getPackageDirective();
132            if (packageDirective == null) return;
133    
134            KtModifierList modifierList = packageDirective.getModifierList();
135            if (modifierList == null) return;
136    
137            for (KtAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
138                KtConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression();
139                if (calleeExpression != null) {
140                    KtReferenceExpression reference = calleeExpression.getConstructorReferenceExpression();
141                    if (reference != null) {
142                        trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
143                    }
144                }
145            }
146            annotationChecker.check(packageDirective, trace, null);
147            ModifierCheckerCore.INSTANCE$.check(packageDirective, trace, null);
148        }
149    
150        private void checkTypesInClassHeader(@NotNull KtClassOrObject classOrObject) {
151            for (KtDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
152                checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
153            }
154    
155            if (!(classOrObject instanceof KtClass)) return;
156            KtClass ktClass = (KtClass) classOrObject;
157    
158            for (KtTypeParameter jetTypeParameter : ktClass.getTypeParameters()) {
159                checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
160                checkFinalUpperBounds(jetTypeParameter.getExtendsBound());
161            }
162    
163            for (KtTypeConstraint constraint : ktClass.getTypeConstraints()) {
164                checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
165                checkFinalUpperBounds(constraint.getBoundTypeReference());
166            }
167        }
168    
169        private void checkBoundsForTypeInClassHeader(@Nullable KtTypeReference typeReference) {
170            if (typeReference != null) {
171                KotlinType type = trace.getBindingContext().get(TYPE, typeReference);
172                if (type != null) {
173                    DescriptorResolver.checkBounds(typeReference, type, trace);
174                }
175            }
176        }
177    
178        private void checkFinalUpperBounds(@Nullable KtTypeReference typeReference) {
179            if (typeReference != null) {
180                KotlinType type = trace.getBindingContext().get(TYPE, typeReference);
181                if (type != null) {
182                    DescriptorResolver.checkUpperBoundType(typeReference, type, trace);
183                }
184            }
185        }
186    
187        private void checkSupertypesForConsistency(
188                @NotNull KtClassOrObject classOrObject,
189                @NotNull ClassDescriptor classDescriptor
190        ) {
191            checkSupertypesForConsistency(classDescriptor, classOrObject);
192        }
193    
194        private void checkSupertypesForConsistency(
195                @NotNull KtTypeParameter typeParameter,
196                @NotNull TypeParameterDescriptor typeParameterDescriptor
197        ) {
198            checkSupertypesForConsistency(typeParameterDescriptor, typeParameter);
199        }
200    
201        private void checkSupertypesForConsistency(
202                @NotNull ClassifierDescriptor classifierDescriptor,
203                @NotNull PsiElement sourceElement
204        ) {
205            Multimap<TypeConstructor, TypeProjection> multimap =
206                    SubstitutionUtils.buildDeepSubstitutionMultimap(classifierDescriptor.getDefaultType());
207            for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
208                Collection<TypeProjection> projections = entry.getValue();
209                if (projections.size() > 1) {
210                    TypeConstructor typeConstructor = entry.getKey();
211                    DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
212                    assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
213                    TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
214    
215                    // Immediate arguments of supertypes cannot be projected
216                    Set<KotlinType> conflictingTypes = Sets.newLinkedHashSet();
217                    for (TypeProjection projection : projections) {
218                        conflictingTypes.add(projection.getType());
219                    }
220                    removeDuplicateTypes(conflictingTypes);
221                    if (conflictingTypes.size() > 1) {
222                        DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
223                        assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
224                        if (sourceElement instanceof KtClassOrObject) {
225                            KtDelegationSpecifierList delegationSpecifierList = ((KtClassOrObject) sourceElement).getDelegationSpecifierList();
226                            assert delegationSpecifierList != null;
227                            //                        trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
228                            trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
229                                                 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
230                                                     conflictingTypes));
231                        }
232                        else if (sourceElement instanceof KtTypeParameter) {
233                            trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS
234                                                 .on((KtTypeParameter) sourceElement, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
235                                                     conflictingTypes));
236                        }
237                    }
238                }
239            }
240        }
241    
242        private void checkClassExposedType(@NotNull KtClassOrObject klass, @NotNull ClassDescriptor classDescriptor) {
243            checkExposedSupertypes(klass, classDescriptor);
244            checkExposedParameterBounds(klass, classDescriptor);
245    
246            if (classDescriptor.getUnsubstitutedPrimaryConstructor() != null && klass.getPrimaryConstructor() != null) {
247                checkFunctionExposedType(klass.getPrimaryConstructor(), classDescriptor.getUnsubstitutedPrimaryConstructor());
248            }
249        }
250    
251        private void checkExposedParameterBounds(@NotNull KtClassOrObject klass, @NotNull ClassDescriptor classDescriptor) {
252            EffectiveVisibility classVisibility = EffectiveVisibility.Companion.forClass(classDescriptor);
253            List<KtTypeParameter> typeParameterList = klass.getTypeParameters();
254            int i = 0;
255            for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) {
256                if (i >= typeParameterList.size()) return;
257                for (KotlinType upperBound : typeParameterDescriptor.getUpperBounds()) {
258                    EffectiveVisibility upperBoundVisibility = EffectiveVisibility.Companion.forType(upperBound);
259                    if (!upperBoundVisibility.sameOrMorePermissive(classVisibility)) {
260                        KtTypeParameter typeParameter = typeParameterList.get(i);
261                        trace.report(EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameter, classVisibility, upperBoundVisibility));
262                        break;
263                    }
264                }
265                i++;
266            }
267        }
268    
269        private void checkExposedSupertypes(@NotNull KtClassOrObject klass, @NotNull ClassDescriptor classDescriptor) {
270            EffectiveVisibility classVisibility = EffectiveVisibility.Companion.forClass(classDescriptor);
271            boolean isInterface = classDescriptor.getKind() == ClassKind.INTERFACE;
272            List<KtDelegationSpecifier> delegationList = klass.getDelegationSpecifiers();
273            int i = -1;
274            for (KotlinType superType : classDescriptor.getTypeConstructor().getSupertypes()) {
275                i++;
276                if (i >= delegationList.size()) return;
277                ClassDescriptor superDescriptor = TypeUtils.getClassDescriptor(superType);
278                if (superDescriptor == null) {
279                    continue;
280                }
281                boolean superIsInterface = superDescriptor.getKind() == ClassKind.INTERFACE;
282                if (superIsInterface != isInterface) {
283                    continue;
284                }
285                EffectiveVisibility superTypeVisibility = EffectiveVisibility.Companion.forType(superType);
286                if (!superTypeVisibility.sameOrMorePermissive(classVisibility)) {
287                    if (isInterface) {
288                        trace.report(EXPOSED_SUPER_INTERFACE.on(delegationList.get(i), classVisibility, superTypeVisibility));
289                    }
290                    else {
291                        trace.report(EXPOSED_SUPER_CLASS.on(delegationList.get(i), classVisibility, superTypeVisibility));
292                    }
293                }
294            }
295        }
296    
297        private static void removeDuplicateTypes(Set<KotlinType> conflictingTypes) {
298            for (Iterator<KotlinType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
299                KotlinType type = iterator.next();
300                for (KotlinType otherType : conflictingTypes) {
301                    boolean subtypeOf = KotlinTypeChecker.DEFAULT.equalTypes(type, otherType);
302                    if (type != otherType && subtypeOf) {
303                        iterator.remove();
304                        break;
305                    }
306                }
307            }
308        }
309    
310        private void checkObject(KtObjectDeclaration declaration, ClassDescriptor classDescriptor) {
311            if  (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) {
312                trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor));
313            }
314        }
315    
316        private void checkClass(BodiesResolveContext c, KtClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
317            checkOpenMembers(classDescriptor);
318            checkTypeParameters(aClass);
319            checkTypeParameterConstraints(aClass);
320            FiniteBoundRestrictionChecker.check(aClass, classDescriptor, trace);
321            NonExpansiveInheritanceRestrictionChecker.check(aClass, classDescriptor, trace);
322    
323            if (aClass.isInterface()) {
324                checkConstructorInInterface(aClass);
325                checkMethodsOfAnyInInterface(classDescriptor);
326                if (aClass.isLocal() && !(classDescriptor.getContainingDeclaration() instanceof ClassDescriptor)) {
327                    trace.report(LOCAL_INTERFACE_NOT_ALLOWED.on(aClass, classDescriptor));
328                }
329            }
330            else if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
331                checkAnnotationClassWithBody(aClass);
332                checkValOnAnnotationParameter(aClass);
333            }
334            else if (aClass instanceof KtEnumEntry) {
335                checkEnumEntry((KtEnumEntry) aClass, classDescriptor);
336            }
337            for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
338                if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
339                KtNamedDeclaration member = (KtNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor);
340                if (member instanceof KtFunction && memberDescriptor instanceof FunctionDescriptor) {
341                    checkFunctionExposedType((KtFunction) member, (FunctionDescriptor) memberDescriptor);
342                }
343            }
344        }
345    
346        private void checkPrimaryConstructor(KtClassOrObject classOrObject, ClassDescriptor classDescriptor) {
347            ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
348            KtPrimaryConstructor declaration = classOrObject.getPrimaryConstructor();
349            if (primaryConstructor == null || declaration == null) return;
350    
351            for (KtParameter parameter : declaration.getValueParameters()) {
352                PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
353                if (propertyDescriptor != null) {
354                    modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor);
355                    checkPropertyLateInit(parameter, propertyDescriptor);
356                }
357            }
358    
359            if (declaration.getModifierList() != null && !declaration.hasConstructorKeyword()) {
360                trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList()));
361            }
362    
363            if (!(classOrObject instanceof KtClass)) {
364                trace.report(CONSTRUCTOR_IN_OBJECT.on(declaration));
365            }
366    
367            checkConstructorDeclaration(primaryConstructor, declaration);
368        }
369    
370        private void checkTypeParameters(KtTypeParameterListOwner typeParameterListOwner) {
371            // TODO: Support annotation for type parameters
372            for (KtTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
373                AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
374    
375                TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
376                if (typeParameter != null) {
377                    DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
378                }
379            }
380        }
381    
382        private void checkTypeParameterConstraints(KtTypeParameterListOwner typeParameterListOwner) {
383            List<KtTypeConstraint> constraints = typeParameterListOwner.getTypeConstraints();
384            if (!constraints.isEmpty()) {
385                for (KtTypeParameter typeParameter : typeParameterListOwner.getTypeParameters()) {
386                    if (typeParameter.getExtendsBound() != null && hasConstraints(typeParameter, constraints)) {
387                        trace.report(MISPLACED_TYPE_PARAMETER_CONSTRAINTS.on(typeParameter));
388                    }
389                    TypeParameterDescriptor descriptor = trace.get(TYPE_PARAMETER, typeParameter);
390                    if (descriptor != null) {
391                        checkSupertypesForConsistency(typeParameter, descriptor);
392                    }
393                }
394            }
395        }
396    
397        private static boolean hasConstraints(KtTypeParameter typeParameter, List<KtTypeConstraint> constraints) {
398            for (KtTypeConstraint constraint : constraints) {
399                KtSimpleNameExpression parameterName = constraint.getSubjectTypeParameterName();
400                if (parameterName != null && parameterName.getText().equals(typeParameter.getName())) {
401                    return true;
402                }
403            }
404            return false;
405        }
406    
407        private void checkConstructorInInterface(KtClass klass) {
408            KtPrimaryConstructor primaryConstructor = klass.getPrimaryConstructor();
409            if (primaryConstructor != null) {
410                trace.report(CONSTRUCTOR_IN_INTERFACE.on(primaryConstructor));
411            }
412        }
413    
414        private void checkMethodsOfAnyInInterface(ClassDescriptorWithResolutionScopes classDescriptor) {
415            for (CallableMemberDescriptor declaredCallableMember : classDescriptor.getDeclaredCallableMembers()) {
416                if (!(declaredCallableMember instanceof FunctionDescriptor)) continue;
417                FunctionDescriptor functionDescriptor = (FunctionDescriptor) declaredCallableMember;
418    
419                PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
420                if (!(declaration instanceof KtNamedFunction)) continue;
421                KtNamedFunction functionDeclaration = (KtNamedFunction) declaration;
422    
423                if (isHidingParentMemberIfPresent(declaredCallableMember)) continue;
424    
425                if (isImplementingMethodOfAny(declaredCallableMember)) {
426                    trace.report(METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE.on(functionDeclaration));
427                }
428            }
429        }
430    
431        private static final Set<String> METHOD_OF_ANY_NAMES = ImmutableSet.of("toString", "hashCode", "equals");
432    
433        private static boolean isImplementingMethodOfAny(CallableMemberDescriptor member) {
434            if (!METHOD_OF_ANY_NAMES.contains(member.getName().asString())) return false;
435            if (member.getModality() == Modality.ABSTRACT) return false;
436    
437            return isImplementingMethodOfAnyInternal(member, new HashSet<ClassDescriptor>());
438        }
439    
440        private static boolean isImplementingMethodOfAnyInternal(CallableMemberDescriptor member, Set<ClassDescriptor> visitedClasses) {
441            for (CallableMemberDescriptor overridden : member.getOverriddenDescriptors()) {
442                DeclarationDescriptor containingDeclaration = overridden.getContainingDeclaration();
443                if (!(containingDeclaration instanceof ClassDescriptor)) continue;
444                ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
445                if (visitedClasses.contains(containingClass)) continue;
446    
447                if (DescriptorUtils.getFqName(containingClass).equals(KotlinBuiltIns.FQ_NAMES.any)) {
448                    return true;
449                }
450    
451                if (isHidingParentMemberIfPresent(overridden)) continue;
452    
453                visitedClasses.add(containingClass);
454    
455                if (isImplementingMethodOfAnyInternal(overridden, visitedClasses)) {
456                    return true;
457                }
458            }
459    
460            return false;
461        }
462    
463        private static boolean isHidingParentMemberIfPresent(CallableMemberDescriptor member) {
464            KtNamedDeclaration declaration = (KtNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(member);
465            if (declaration != null) {
466                KtModifierList modifierList = declaration.getModifierList();
467                return modifierList == null || !modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD);
468            }
469            return false;
470        }
471    
472        private void checkAnnotationClassWithBody(KtClassOrObject classOrObject) {
473            if (classOrObject.getBody() != null) {
474                trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
475            }
476        }
477    
478        private void checkValOnAnnotationParameter(KtClass aClass) {
479            for (KtParameter parameter : aClass.getPrimaryConstructorParameters()) {
480                if (!parameter.hasValOrVar()) {
481                    trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
482                }
483            }
484        }
485    
486        private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
487            if (classCanHaveOpenMembers(classDescriptor)) return;
488    
489            for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
490                if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
491                KtNamedDeclaration member = (KtNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor);
492                if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) {
493                    trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
494                }
495            }
496        }
497    
498        private void checkProperty(KtProperty property, PropertyDescriptor propertyDescriptor) {
499            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
500            if (containingDeclaration instanceof ClassDescriptor) {
501                checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
502            }
503            checkPropertyLateInit(property, propertyDescriptor);
504            checkPropertyInitializer(property, propertyDescriptor);
505            checkAccessors(property, propertyDescriptor);
506            checkTypeParameterConstraints(property);
507            checkPropertyExposedType(property, propertyDescriptor);
508            checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor);
509        }
510    
511        private void checkPropertyTypeParametersAreUsedInReceiverType(@NotNull PropertyDescriptor descriptor) {
512            for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
513                if (isTypeParameterUsedInReceiverType(typeParameter, descriptor)) continue;
514    
515                PsiElement typeParameterPsi = DescriptorToSourceUtils.getSourceFromDescriptor(typeParameter);
516                if (typeParameterPsi instanceof KtTypeParameter) {
517                    trace.report(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER.on((KtTypeParameter) typeParameterPsi));
518                }
519            }
520        }
521    
522        private static boolean isTypeParameterUsedInReceiverType(
523                @NotNull final TypeParameterDescriptor parameter,
524                @NotNull PropertyDescriptor descriptor
525        ) {
526            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
527            if (receiverParameter == null) return false;
528    
529            return TypeUtils.containsSpecialType(receiverParameter.getType(), new Function1<KotlinType, Boolean>() {
530                @Override
531                public Boolean invoke(KotlinType type) {
532                    return parameter.equals(type.getConstructor().getDeclarationDescriptor());
533                }
534            });
535        }
536    
537        private void checkPropertyLateInit(@NotNull KtCallableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor) {
538            KtModifierList modifierList = property.getModifierList();
539            if (modifierList == null) return;
540            PsiElement modifier = modifierList.getModifier(KtTokens.LATEINIT_KEYWORD);
541            if (modifier == null) return;
542    
543            if (!propertyDescriptor.isVar()) {
544                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable properties"));
545            }
546    
547            boolean returnTypeIsNullable = true;
548            boolean returnTypeIsPrimitive = true;
549    
550            KotlinType returnType = propertyDescriptor.getReturnType();
551            if (returnType != null) {
552                returnTypeIsNullable = TypeUtils.isNullableType(returnType);
553                returnTypeIsPrimitive = KotlinBuiltIns.isPrimitiveType(returnType);
554            }
555    
556            if (returnTypeIsNullable) {
557                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on nullable properties"));
558            }
559    
560            if (returnTypeIsPrimitive) {
561                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primitive type properties"));
562            }
563    
564            boolean isAbstract = propertyDescriptor.getModality() == Modality.ABSTRACT;
565            if (isAbstract) {
566                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on abstract properties"));
567            }
568    
569            if (property instanceof KtParameter) {
570                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primary constructor parameters"));
571            }
572    
573            boolean hasDelegateExpressionOrInitializer = false;
574            if (property instanceof KtProperty) {
575                hasDelegateExpressionOrInitializer = ((KtProperty) property).hasDelegateExpressionOrInitializer();
576                if (hasDelegateExpressionOrInitializer) {
577                    trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier,
578                            "is not allowed on properties with initializer or on delegated properties"));
579                }
580            }
581    
582            PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
583            PropertySetterDescriptor setter = propertyDescriptor.getSetter();
584    
585            boolean customGetterOrSetter = false;
586            if (getter != null) {
587                customGetterOrSetter = getter.hasBody();
588            }
589            if (setter != null) {
590                customGetterOrSetter |= setter.hasBody();
591            }
592    
593            if (!hasDelegateExpressionOrInitializer && customGetterOrSetter) {
594                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on properties with a custom getter or setter"));
595            }
596    
597            boolean hasBackingField =
598                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
599    
600            if (!isAbstract && !customGetterOrSetter && !hasDelegateExpressionOrInitializer && !hasBackingField) {
601                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on properties without backing field"));
602            }
603    
604            if (propertyDescriptor.getExtensionReceiverParameter() != null) {
605                trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on extension properties"));
606            }
607        }
608    
609        private void checkPropertyAbstractness(
610                @NotNull KtProperty property,
611                @NotNull PropertyDescriptor propertyDescriptor,
612                @NotNull ClassDescriptor classDescriptor
613        ) {
614            KtPropertyAccessor getter = property.getGetter();
615            KtPropertyAccessor setter = property.getSetter();
616            KtModifierList modifierList = property.getModifierList();
617    
618            if (modifierList != null && modifierList.hasModifier(KtTokens.ABSTRACT_KEYWORD)) { //has abstract modifier
619                if (!classCanHaveAbstractMembers(classDescriptor)) {
620                    String name = property.getName();
621                    trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
622                    return;
623                }
624                if (classDescriptor.getKind() == ClassKind.INTERFACE) {
625                    trace.report(ABSTRACT_MODIFIER_IN_INTERFACE.on(property));
626                }
627            }
628    
629            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
630                KtExpression initializer = property.getInitializer();
631                if (initializer != null) {
632                    trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
633                }
634                KtPropertyDelegate delegate = property.getDelegate();
635                if (delegate != null) {
636                    trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
637                }
638                if (getter != null && getter.hasBody()) {
639                    trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
640                }
641                if (setter != null && setter.hasBody()) {
642                    trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter));
643                }
644            }
645        }
646    
647        private void checkPropertyInitializer(@NotNull KtProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
648            KtPropertyAccessor getter = property.getGetter();
649            KtPropertyAccessor setter = property.getSetter();
650            boolean hasAccessorImplementation = (getter != null && getter.hasBody()) ||
651                                                (setter != null && setter.hasBody());
652    
653            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
654            boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.INTERFACE;
655            if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
656                if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null) {
657                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
658                }
659                if (inTrait && property.hasModifier(KtTokens.PRIVATE_KEYWORD) && !property.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
660                    trace.report(PRIVATE_PROPERTY_IN_INTERFACE.on(property));
661                }
662                return;
663            }
664            KtExpression initializer = property.getInitializer();
665            KtPropertyDelegate delegate = property.getDelegate();
666            boolean backingFieldRequired =
667                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
668    
669            if (inTrait && backingFieldRequired && hasAccessorImplementation) {
670                trace.report(BACKING_FIELD_IN_INTERFACE.on(property));
671            }
672    
673            if (initializer == null && delegate == null) {
674                boolean error = false;
675                if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit() &&
676                    Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, propertyDescriptor))) {
677                    if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
678                        error = true;
679                        trace.report(MUST_BE_INITIALIZED.on(property));
680                    }
681                    else {
682                        error = true;
683                        trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
684                    }
685                }
686                if (!error && property.getTypeReference() == null) {
687                    trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
688                }
689                if (inTrait && property.hasModifier(KtTokens.FINAL_KEYWORD) && backingFieldRequired) {
690                    trace.report(FINAL_PROPERTY_IN_INTERFACE.on(property));
691                }
692                return;
693            }
694    
695            if (inTrait) {
696                if (delegate != null) {
697                    trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate));
698                }
699                else {
700                    trace.report(PROPERTY_INITIALIZER_IN_INTERFACE.on(initializer));
701                }
702            }
703            else if (delegate == null) {
704                if (!backingFieldRequired) {
705                    trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
706                }
707                else if (property.getReceiverTypeReference() != null) {
708                    trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer));
709                }
710            }
711        }
712    
713        private void checkMemberReceiverExposedType(@Nullable KtTypeReference typeReference, @NotNull CallableMemberDescriptor memberDescriptor) {
714            if (typeReference == null) return;
715            ReceiverParameterDescriptor receiverParameterDescriptor = memberDescriptor.getExtensionReceiverParameter();
716            if (receiverParameterDescriptor == null) return;
717            EffectiveVisibility memberVisibility = EffectiveVisibility.Companion.forMember(memberDescriptor);
718            EffectiveVisibility receiverTypeVisibility = EffectiveVisibility.Companion.forType(receiverParameterDescriptor.getType());
719            if (!receiverTypeVisibility.sameOrMorePermissive(memberVisibility)) {
720                trace.report(EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility, receiverTypeVisibility));
721            }
722        }
723    
724        private void checkPropertyExposedType(@NotNull KtProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
725            EffectiveVisibility propertyVisibility = EffectiveVisibility.Companion.forMember(propertyDescriptor);
726            EffectiveVisibility typeVisibility = EffectiveVisibility.Companion.forType(propertyDescriptor.getType());
727            if (!typeVisibility.sameOrMorePermissive(propertyVisibility)) {
728                trace.report(EXPOSED_PROPERTY_TYPE.on(property, propertyVisibility, typeVisibility));
729            }
730            checkMemberReceiverExposedType(property.getReceiverTypeReference(), propertyDescriptor);
731        }
732    
733        protected void checkFunction(KtNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
734            KtTypeParameterList typeParameterList = function.getTypeParameterList();
735            PsiElement nameIdentifier = function.getNameIdentifier();
736            if (typeParameterList != null && nameIdentifier != null &&
737                typeParameterList.getTextRange().getStartOffset() > nameIdentifier.getTextRange().getStartOffset()) {
738                trace.report(DEPRECATED_TYPE_PARAMETER_SYNTAX.on(typeParameterList));
739            }
740            checkTypeParameterConstraints(function);
741    
742            DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
743            boolean hasAbstractModifier = function.hasModifier(KtTokens.ABSTRACT_KEYWORD);
744            boolean hasExternalModifier = function.hasModifier(KtTokens.EXTERNAL_KEYWORD);
745    
746            if (containingDescriptor instanceof ClassDescriptor) {
747                ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
748                boolean inTrait = classDescriptor.getKind() == ClassKind.INTERFACE;
749                if (hasAbstractModifier && !classCanHaveAbstractMembers(classDescriptor)) {
750                    trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
751                }
752                if (hasAbstractModifier && inTrait) {
753                    trace.report(ABSTRACT_MODIFIER_IN_INTERFACE.on(function));
754                }
755                boolean hasBody = function.hasBody();
756                if (hasBody && hasAbstractModifier) {
757                    trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
758                }
759                if (!hasBody && inTrait) {
760                    if (function.hasModifier(KtTokens.FINAL_KEYWORD) && !hasExternalModifier) {
761                        trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
762                    }
763                    if (function.hasModifier(KtTokens.PRIVATE_KEYWORD)) {
764                        trace.report(PRIVATE_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
765                    }
766                }
767                if (!hasBody && !hasAbstractModifier && !hasExternalModifier && !inTrait) {
768                    trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
769                }
770                return;
771            }
772            if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier) {
773                trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
774            }
775            if (TypeUtilsKt.isNothing(functionDescriptor.getReturnType()) && !function.hasDeclaredReturnType()) {
776                trace.report(IMPLICIT_NOTHING_RETURN_TYPE.on(function.getNameIdentifier() != null ? function.getNameIdentifier() : function));
777            }
778            checkFunctionExposedType(function, functionDescriptor);
779        }
780    
781        private void checkFunctionExposedType(@NotNull KtFunction function, @NotNull FunctionDescriptor functionDescriptor) {
782            EffectiveVisibility functionVisibility = EffectiveVisibility.Companion.forMember(functionDescriptor);
783            if (!(function instanceof KtConstructor)) {
784                EffectiveVisibility returnTypeVisibility = EffectiveVisibility.Companion.forType(functionDescriptor.getReturnType());
785                if (!returnTypeVisibility.sameOrMorePermissive(functionVisibility)) {
786                    PsiElement reportOn = function.getNameIdentifier();
787                    if (reportOn == null) {
788                        reportOn = function;
789                    }
790                    trace.report(EXPOSED_FUNCTION_RETURN_TYPE.on(reportOn, functionVisibility, returnTypeVisibility));
791                }
792            }
793            int i = 0;
794            for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
795                EffectiveVisibility typeVisibility = EffectiveVisibility.Companion.forType(parameterDescriptor.getType());
796                if (!typeVisibility.sameOrMorePermissive(functionVisibility) && i < function.getValueParameters().size()) {
797                    trace.report(EXPOSED_PARAMETER_TYPE.on(function.getValueParameters().get(i), functionVisibility, typeVisibility));
798                }
799                i++;
800            }
801            checkMemberReceiverExposedType(function.getReceiverTypeReference(), functionDescriptor);
802        }
803    
804        private void checkAccessors(@NotNull KtProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
805            for (KtPropertyAccessor accessor : property.getAccessors()) {
806                PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
807                assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText();
808                modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor);
809                identifierChecker.checkDeclaration(accessor, trace);
810            }
811            checkAccessor(propertyDescriptor, property.getGetter(), propertyDescriptor.getGetter());
812            checkAccessor(propertyDescriptor, property.getSetter(), propertyDescriptor.getSetter());
813        }
814    
815        private void reportVisibilityModifierDiagnostics(Collection<PsiElement> tokens, DiagnosticFactory0<PsiElement> diagnostic) {
816            for (PsiElement token : tokens) {
817                trace.report(diagnostic.on(token));
818            }
819        }
820    
821        private void checkAccessor(
822                @NotNull PropertyDescriptor propertyDescriptor,
823                @Nullable KtPropertyAccessor accessor,
824                @Nullable PropertyAccessorDescriptor accessorDescriptor
825        ) {
826            if (accessor == null) return;
827            KtModifierList accessorModifierList = accessor.getModifierList();
828            if (accessorModifierList != null && accessorDescriptor != null) {
829                Map<KtModifierKeywordToken, PsiElement> tokens = modifiersChecker.getTokensCorrespondingToModifiers(accessorModifierList, Sets
830                        .newHashSet(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD,
831                                    KtTokens.INTERNAL_KEYWORD));
832                if (accessor.isGetter()) {
833                    if (accessorDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
834                        reportVisibilityModifierDiagnostics(tokens.values(), Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY);
835                    }
836                    else {
837                        reportVisibilityModifierDiagnostics(tokens.values(), Errors.REDUNDANT_MODIFIER_IN_GETTER);
838                    }
839                }
840                else {
841                    if (propertyDescriptor.getModality() == Modality.ABSTRACT
842                        && accessorDescriptor.getVisibility() == Visibilities.PRIVATE
843                        && propertyDescriptor.getVisibility() != Visibilities.PRIVATE) {
844                        reportVisibilityModifierDiagnostics(tokens.values(), Errors.ACCESSOR_VISIBILITY_FOR_ABSTRACT_PROPERTY);
845                    }
846                    else if (propertyDescriptor.isLateInit() && accessorDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
847                        reportVisibilityModifierDiagnostics(tokens.values(), Errors.SETTER_VISIBILITY_DIFFERS_FROM_LATEINIT_VISIBILITY);
848                    }
849                }
850            }
851        }
852    
853        private void checkEnumEntry(@NotNull KtEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
854            DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
855            if (DescriptorUtils.isEnumClass(declaration)) {
856                if (!enumEntry.hasInitializer() && !hasDefaultConstructor((ClassDescriptor) declaration)) {
857                    trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry));
858                }
859            }
860            else {
861                assert DescriptorUtils.isInterface(declaration) : "Enum entry should be declared in enum class: " + classDescriptor;
862            }
863        }
864    
865        private static boolean hasDefaultConstructor(@NotNull ClassDescriptor classDescriptor) {
866            for (ConstructorDescriptor constructor : classDescriptor.getConstructors()) {
867                if (constructor.getValueParameters().isEmpty()) return true;
868            }
869            return false;
870        }
871    }