001 /*
002 * Copyright 2010-2014 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.jet.lang.resolve;
018
019 import com.google.common.collect.Multimap;
020 import com.google.common.collect.Sets;
021 import com.intellij.lang.ASTNode;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.types.*;
028 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
029 import org.jetbrains.jet.lexer.JetModifierKeywordToken;
030 import org.jetbrains.jet.lexer.JetTokens;
031
032 import javax.inject.Inject;
033 import java.util.*;
034
035 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
036 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
037 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE_PARAMETER;
038
039 public class DeclarationsChecker {
040 @NotNull
041 private BindingTrace trace;
042 @NotNull
043 private ModifiersChecker modifiersChecker;
044 @NotNull
045 private DescriptorResolver descriptorResolver;
046
047 @NotNull
048 private AdditionalCheckerProvider additionalCheckerProvider;
049
050 @Inject
051 public void setTrace(@NotNull BindingTrace trace) {
052 this.trace = trace;
053 this.modifiersChecker = new ModifiersChecker(trace);
054 }
055
056 @Inject
057 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
058 this.descriptorResolver = descriptorResolver;
059 }
060
061 @Inject
062 public void setAdditionalCheckerProvider(@NotNull AdditionalCheckerProvider additionalCheckerProvider) {
063 this.additionalCheckerProvider = additionalCheckerProvider;
064 }
065
066 public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
067 for (JetFile file : bodiesResolveContext.getFiles()) {
068 checkModifiersAndAnnotationsInPackageDirective(file);
069 }
070
071 Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses();
072 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) {
073 JetClassOrObject classOrObject = entry.getKey();
074 ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
075 if (!bodiesResolveContext.completeAnalysisNeeded(classOrObject)) continue;
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 runAnnotationCheckers(classOrObject, classDescriptor);
092 }
093
094 Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
095 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
096 JetNamedFunction function = entry.getKey();
097 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
098
099 if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue;
100 checkFunction(function, functionDescriptor);
101 modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor);
102 runAnnotationCheckers(function, functionDescriptor);
103 }
104
105 Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties();
106 for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
107 JetProperty property = entry.getKey();
108 PropertyDescriptor propertyDescriptor = entry.getValue();
109
110 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue;
111 checkProperty(property, propertyDescriptor);
112 modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
113 runAnnotationCheckers(property, propertyDescriptor);
114 }
115
116 }
117
118 private void reportErrorIfHasIllegalModifier(JetModifierListOwner declaration) {
119 if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) {
120 trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration));
121 }
122 if (declaration.hasModifier(JetTokens.ANNOTATION_KEYWORD)) {
123 trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration));
124 }
125 }
126
127 private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) {
128 JetPackageDirective packageDirective = file.getPackageDirective();
129 if (packageDirective == null) return;
130
131 JetModifierList modifierList = packageDirective.getModifierList();
132 if (modifierList == null) return;
133
134 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
135 JetConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression();
136 if (calleeExpression != null) {
137 JetReferenceExpression reference = calleeExpression.getConstructorReferenceExpression();
138 if (reference != null) {
139 trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
140 }
141 }
142 }
143
144 ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace);
145 }
146
147 private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) {
148 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
149 checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
150 }
151
152 if (!(classOrObject instanceof JetClass)) return;
153 JetClass jetClass = (JetClass) classOrObject;
154
155 for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
156 checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
157 checkFinalUpperBounds(jetTypeParameter.getExtendsBound(), false);
158 }
159
160 for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
161 checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
162 checkFinalUpperBounds(constraint.getBoundTypeReference(), constraint.isClassObjectConstraint());
163 }
164 }
165
166 private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) {
167 if (typeReference != null) {
168 JetType type = trace.getBindingContext().get(TYPE, typeReference);
169 if (type != null) {
170 DescriptorResolver.checkBounds(typeReference, type, trace);
171 }
172 }
173 }
174
175 private void checkFinalUpperBounds(@Nullable JetTypeReference typeReference, boolean isClassObjectConstraint) {
176 if (typeReference != null) {
177 JetType type = trace.getBindingContext().get(TYPE, typeReference);
178 if (type != null) {
179 DescriptorResolver.checkUpperBoundType(typeReference, type, isClassObjectConstraint, trace);
180 }
181 }
182 }
183
184 private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) {
185 Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
186 .buildDeepSubstitutionMultimap(classDescriptor.getDefaultType());
187 for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
188 Collection<TypeProjection> projections = entry.getValue();
189 if (projections.size() > 1) {
190 TypeConstructor typeConstructor = entry.getKey();
191 DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
192 assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
193 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
194
195 // Immediate arguments of supertypes cannot be projected
196 Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
197 for (TypeProjection projection : projections) {
198 conflictingTypes.add(projection.getType());
199 }
200 switch (typeParameterDescriptor.getVariance()) {
201 case INVARIANT:
202 // Leave conflicting types as is
203 break;
204 case IN_VARIANCE:
205 // Filter out those who have supertypes in this set (common supertype)
206 Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
207 break;
208 case OUT_VARIANCE:
209 // Filter out those who have subtypes in this set (common subtype)
210 Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
211 break;
212 }
213
214 if (conflictingTypes.size() > 1) {
215 DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
216 assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
217 JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.classDescriptorToDeclaration(classDescriptor);
218 JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
219 assert delegationSpecifierList != null;
220 // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
221 trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
222 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
223 conflictingTypes));
224 }
225 }
226 }
227 }
228
229 private enum Filter {
230 REMOVE_IF_SUBTYPE_IN_THE_SET {
231 @Override
232 public boolean removeNeeded(JetType subject, JetType other) {
233 return JetTypeChecker.DEFAULT.isSubtypeOf(other, subject);
234 }
235 },
236 REMOVE_IF_SUPERTYPE_IN_THE_SET {
237 @Override
238 public boolean removeNeeded(JetType subject, JetType other) {
239 return JetTypeChecker.DEFAULT.isSubtypeOf(subject, other);
240 }
241 };
242
243 private void proceed(Set<JetType> conflictingTypes) {
244 for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
245 JetType type = iterator.next();
246 for (JetType otherType : conflictingTypes) {
247 boolean subtypeOf = removeNeeded(type, otherType);
248 if (type != otherType && subtypeOf) {
249 iterator.remove();
250 break;
251 }
252 }
253 }
254 }
255
256 public abstract boolean removeNeeded(JetType subject, JetType other);
257 }
258
259 private void checkObject(JetObjectDeclaration declaration, ClassDescriptor classDescriptor) {
260 reportErrorIfHasIllegalModifier(declaration);
261 if (declaration.isLocal() && !declaration.isClassObject() && !declaration.isObjectLiteral()) {
262 trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor));
263 }
264 }
265
266 private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
267 checkOpenMembers(classDescriptor);
268 if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
269 checkTypeParameters(aClass);
270 }
271 if (aClass.isTrait()) {
272 checkTraitModifiers(aClass);
273 checkConstructorInTrait(aClass);
274 }
275 else if (aClass.isAnnotation()) {
276 checkAnnotationClassWithBody(aClass);
277 checkValOnAnnotationParameter(aClass);
278 }
279 else if (aClass.isEnum()) {
280 checkEnumModifiers(aClass);
281 if (aClass.isLocal()) {
282 trace.report(LOCAL_ENUM_NOT_ALLOWED.on(aClass, classDescriptor));
283 }
284 }
285 else if (aClass instanceof JetEnumEntry) {
286 checkEnumEntry((JetEnumEntry) aClass, classDescriptor);
287 }
288 }
289
290 private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
291 // TODO: Support annotation for type parameters
292 for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
293 AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
294
295 TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
296 if (typeParameter != null) {
297 DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
298 }
299 }
300 }
301
302 private void checkConstructorInTrait(JetClass klass) {
303 JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
304 if (primaryConstructorParameterList != null) {
305 trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructorParameterList));
306 }
307 }
308
309 private void checkTraitModifiers(JetClass aClass) {
310 reportErrorIfHasIllegalModifier(aClass);
311 JetModifierList modifierList = aClass.getModifierList();
312 if (modifierList == null) return;
313 if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) {
314 trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(aClass));
315 }
316 if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
317 trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass));
318 }
319 if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) {
320 trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass));
321 }
322 }
323
324 private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) {
325 if (classOrObject.getBody() != null) {
326 trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
327 }
328 }
329
330 private void checkValOnAnnotationParameter(JetClass aClass) {
331 for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
332 if (!parameter.hasValOrVarNode()) {
333 trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
334 }
335 }
336 }
337
338 private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
339 for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
340 if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
341 JetNamedDeclaration member = (JetNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor);
342 if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
343 trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
344 }
345 }
346 }
347
348 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
349 reportErrorIfHasIllegalModifier(property);
350 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
351 if (containingDeclaration instanceof ClassDescriptor) {
352 checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
353 }
354 else {
355 modifiersChecker.checkIllegalModalityModifiers(property);
356 }
357 checkPropertyInitializer(property, propertyDescriptor);
358 checkAccessors(property, propertyDescriptor);
359 checkDeclaredTypeInPublicMember(property, propertyDescriptor);
360 }
361
362 private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) {
363 boolean hasDeferredType;
364 if (member instanceof JetProperty) {
365 hasDeferredType = ((JetProperty) member).getTypeRef() == null && DescriptorResolver.hasBody((JetProperty) member);
366 }
367 else {
368 assert member instanceof JetFunction;
369 JetFunction function = (JetFunction) member;
370 hasDeferredType = function.getReturnTypeRef() == null && function.hasBody() && !function.hasBlockBody();
371 }
372 if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) {
373 trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member));
374 }
375 }
376
377 private void checkPropertyAbstractness(
378 @NotNull JetProperty property,
379 @NotNull PropertyDescriptor propertyDescriptor,
380 @NotNull ClassDescriptor classDescriptor
381 ) {
382 JetPropertyAccessor getter = property.getGetter();
383 JetPropertyAccessor setter = property.getSetter();
384 JetModifierList modifierList = property.getModifierList();
385 ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
386
387 if (abstractNode != null) { //has abstract modifier
388 if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
389 String name = property.getName();
390 trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
391 return;
392 }
393 if (classDescriptor.getKind() == ClassKind.TRAIT) {
394 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property));
395 }
396 }
397
398 if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
399 JetType returnType = propertyDescriptor.getReturnType();
400 if (returnType instanceof DeferredType) {
401 returnType = ((DeferredType) returnType).getDelegate();
402 }
403
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.getTypeRef() == 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.TRAIT;
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.FALSE.equals(trace.getBindingContext().get(BindingContext.IS_INITIALIZED, 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.getTypeRef() == 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.getReceiverTypeRef() != 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.TRAIT;
492 boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS;
493 boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT;
494 if (hasAbstractModifier && !inAbstractClass && !inEnum) {
495 trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
496 }
497 if (hasAbstractModifier && inTrait) {
498 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
499 }
500 boolean hasBody = function.hasBody();
501 if (hasBody && hasAbstractModifier) {
502 trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
503 }
504 if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
505 trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
506 }
507 if (!hasBody && !hasAbstractModifier && !inTrait) {
508 trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
509 }
510 return;
511 }
512 modifiersChecker.checkIllegalModalityModifiers(function);
513 if (!function.hasBody() && !hasAbstractModifier) {
514 trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
515 }
516 }
517
518 private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
519 for (JetPropertyAccessor accessor : property.getAccessors()) {
520 modifiersChecker.checkIllegalModalityModifiers(accessor);
521 }
522 JetPropertyAccessor getter = property.getGetter();
523 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
524 JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null;
525 if (getterModifierList != null && getterDescriptor != null) {
526 Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets
527 .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD,
528 JetTokens.INTERNAL_KEYWORD));
529 if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
530 for (ASTNode node : nodes.values()) {
531 trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi()));
532 }
533 }
534 else {
535 for (ASTNode node : nodes.values()) {
536 trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi()));
537 }
538 }
539 }
540 }
541
542 private void checkEnumModifiers(JetClass aClass) {
543 if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) {
544 trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass));
545 }
546 }
547
548 private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
549 DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
550 assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor;
551 ClassDescriptor enumClass = (ClassDescriptor) declaration;
552
553 List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers();
554 ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor();
555 assert constructor != null;
556 if (!constructor.getValueParameters().isEmpty() && delegationSpecifiers.isEmpty()) {
557 trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass));
558 }
559
560 for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
561 JetTypeReference typeReference = delegationSpecifier.getTypeReference();
562 if (typeReference != null) {
563 JetType type = trace.getBindingContext().get(TYPE, typeReference);
564 if (type != null) {
565 JetType enumType = enumClass.getDefaultType();
566 if (!type.getConstructor().equals(enumType.getConstructor())) {
567 trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass));
568 }
569 }
570 }
571 }
572 }
573
574 private void runAnnotationCheckers(@NotNull JetDeclaration declaration, @NotNull MemberDescriptor descriptor) {
575 for (AnnotationChecker checker : additionalCheckerProvider.getAnnotationCheckers()) {
576 checker.check(declaration, descriptor, trace);
577 }
578 }
579 }