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