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 com.intellij.psi.PsiElement;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.diagnostics.Errors;
027 import org.jetbrains.jet.lang.psi.*;
028 import org.jetbrains.jet.lang.types.*;
029 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
030 import org.jetbrains.jet.lexer.JetKeywordToken;
031 import org.jetbrains.jet.lexer.JetModifierKeywordToken;
032 import org.jetbrains.jet.lexer.JetTokens;
033
034 import javax.inject.Inject;
035 import java.util.*;
036
037 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
038 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
039 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE_PARAMETER;
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 @Inject
050 public void setTrace(@NotNull BindingTrace trace) {
051 this.trace = trace;
052 this.modifiersChecker = new ModifiersChecker(trace);
053 }
054
055 @Inject
056 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
057 this.descriptorResolver = descriptorResolver;
058 }
059
060 public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
061 for (JetFile file : bodiesResolveContext.getFiles()) {
062 checkModifiersAndAnnotationsInPackageDirective(file);
063 }
064
065 Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses();
066 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) {
067 JetClassOrObject classOrObject = entry.getKey();
068 ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
069 if (!bodiesResolveContext.completeAnalysisNeeded(classOrObject)) continue;
070
071 checkSupertypesForConsistency(classDescriptor);
072 checkTypesInClassHeader(classOrObject);
073
074 if (classOrObject instanceof JetClass) {
075 JetClass jetClass = (JetClass) classOrObject;
076 checkClass(bodiesResolveContext, jetClass, classDescriptor);
077 descriptorResolver.checkNamesInConstraints(
078 jetClass, classDescriptor, classDescriptor.getScopeForClassHeaderResolution(), trace);
079 }
080 else if (classOrObject instanceof JetObjectDeclaration) {
081 checkObject((JetObjectDeclaration) classOrObject);
082 }
083
084 modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
085 }
086
087 Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions();
088 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) {
089 JetNamedFunction function = entry.getKey();
090 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
091
092 if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue;
093 checkFunction(function, functionDescriptor);
094 modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor);
095 }
096
097 Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties();
098 for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
099 JetProperty property = entry.getKey();
100 PropertyDescriptor propertyDescriptor = entry.getValue();
101
102 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue;
103 checkProperty(property, propertyDescriptor);
104 modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor);
105 }
106
107 }
108
109 private void reportErrorIfHasIllegalModifier(JetModifierListOwner declaration) {
110 if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) {
111 trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration));
112 }
113 if (declaration.hasModifier(JetTokens.ANNOTATION_KEYWORD)) {
114 trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration));
115 }
116 }
117
118 private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) {
119 JetPackageDirective packageDirective = file.getPackageDirective();
120 if (packageDirective == null) return;
121
122 PsiElement firstChild = packageDirective.getFirstChild();
123 if (!(firstChild instanceof JetModifierList)) return;
124 JetModifierList modifierList = (JetModifierList) firstChild;
125
126 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
127 JetConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression();
128 if (calleeExpression != null) {
129 JetReferenceExpression reference = calleeExpression.getConstructorReferenceExpression();
130 if (reference != null) {
131 trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
132 }
133 }
134 }
135
136 for (ASTNode node : modifierList.getModifierNodes()) {
137 trace.report(ILLEGAL_MODIFIER.on(node.getPsi(), (JetModifierKeywordToken) node.getElementType()));
138 }
139 }
140
141 private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) {
142 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
143 checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
144 }
145
146 if (!(classOrObject instanceof JetClass)) return;
147 JetClass jetClass = (JetClass) classOrObject;
148
149 for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
150 checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
151 checkFinalUpperBounds(jetTypeParameter.getExtendsBound(), false);
152 }
153
154 for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
155 checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
156 checkFinalUpperBounds(constraint.getBoundTypeReference(), constraint.isClassObjectConstraint());
157 }
158 }
159
160 private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) {
161 if (typeReference != null) {
162 JetType type = trace.getBindingContext().get(TYPE, typeReference);
163 if (type != null) {
164 DescriptorResolver.checkBounds(typeReference, type, trace);
165 }
166 }
167 }
168
169 private void checkFinalUpperBounds(@Nullable JetTypeReference typeReference, boolean isClassObjectConstraint) {
170 if (typeReference != null) {
171 JetType type = trace.getBindingContext().get(TYPE, typeReference);
172 if (type != null) {
173 DescriptorResolver.checkUpperBoundType(typeReference, type, isClassObjectConstraint, trace);
174 }
175 }
176 }
177
178 private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) {
179 Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
180 .buildDeepSubstitutionMultimap(classDescriptor.getDefaultType());
181 for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
182 Collection<TypeProjection> projections = entry.getValue();
183 if (projections.size() > 1) {
184 TypeConstructor typeConstructor = entry.getKey();
185 DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
186 assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
187 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
188
189 // Immediate arguments of supertypes cannot be projected
190 Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
191 for (TypeProjection projection : projections) {
192 conflictingTypes.add(projection.getType());
193 }
194 switch (typeParameterDescriptor.getVariance()) {
195 case INVARIANT:
196 // Leave conflicting types as is
197 break;
198 case IN_VARIANCE:
199 // Filter out those who have supertypes in this set (common supertype)
200 Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
201 break;
202 case OUT_VARIANCE:
203 // Filter out those who have subtypes in this set (common subtype)
204 Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
205 break;
206 }
207
208 if (conflictingTypes.size() > 1) {
209 DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
210 assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
211 JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
212 .classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
213 JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
214 assert delegationSpecifierList != null;
215 // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
216 trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
217 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
218 conflictingTypes));
219 }
220 }
221 }
222 }
223
224 private enum Filter {
225 REMOVE_IF_SUBTYPE_IN_THE_SET {
226 @Override
227 public boolean removeNeeded(JetType subject, JetType other) {
228 return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject);
229 }
230 },
231 REMOVE_IF_SUPERTYPE_IN_THE_SET {
232 @Override
233 public boolean removeNeeded(JetType subject, JetType other) {
234 return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other);
235 }
236 };
237
238 private void proceed(Set<JetType> conflictingTypes) {
239 for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
240 JetType type = iterator.next();
241 for (JetType otherType : conflictingTypes) {
242 boolean subtypeOf = removeNeeded(type, otherType);
243 if (type != otherType && subtypeOf) {
244 iterator.remove();
245 break;
246 }
247 }
248 }
249 }
250
251 public abstract boolean removeNeeded(JetType subject, JetType other);
252 }
253
254 private void checkObject(JetObjectDeclaration declaration) {
255 reportErrorIfHasIllegalModifier(declaration);
256 }
257
258 private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
259 checkOpenMembers(classDescriptor);
260 if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
261 checkTypeParameters(aClass);
262 }
263 if (aClass.isTrait()) {
264 checkTraitModifiers(aClass);
265 checkConstructorInTrait(aClass);
266 }
267 else if (aClass.isAnnotation()) {
268 checkAnnotationClassWithBody(aClass);
269 checkValOnAnnotationParameter(aClass);
270 }
271 else if (aClass.isEnum()) {
272 checkEnumModifiers(aClass);
273 }
274 else if (aClass instanceof JetEnumEntry) {
275 checkEnumEntry((JetEnumEntry) aClass, classDescriptor);
276 }
277 }
278
279 private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
280 // TODO: Support annotation for type parameters
281 for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
282 AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace);
283
284 TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter);
285 if (typeParameter != null) {
286 DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter);
287 }
288 }
289 }
290
291 private void checkConstructorInTrait(JetClass klass) {
292 JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
293 if (primaryConstructorParameterList != null) {
294 trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructorParameterList));
295 }
296 }
297
298 private void checkTraitModifiers(JetClass aClass) {
299 reportErrorIfHasIllegalModifier(aClass);
300 JetModifierList modifierList = aClass.getModifierList();
301 if (modifierList == null) return;
302 if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) {
303 trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(modifierList.getModifierNode(JetTokens.FINAL_KEYWORD).getPsi()));
304 }
305 if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
306 trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass));
307 }
308 if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) {
309 trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass));
310 }
311 }
312
313 private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) {
314 if (classOrObject.getBody() != null) {
315 trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody()));
316 }
317 }
318
319 private void checkValOnAnnotationParameter(JetClass aClass) {
320 for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
321 if (parameter.getValOrVarNode() == null) {
322 trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter));
323 }
324 }
325 }
326
327 private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) {
328 for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) {
329 if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue;
330 JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), memberDescriptor);
331 if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) {
332 trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member));
333 }
334 }
335 }
336
337 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
338 reportErrorIfHasIllegalModifier(property);
339 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
340 if (containingDeclaration instanceof ClassDescriptor) {
341 checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration);
342 }
343 else {
344 modifiersChecker.checkIllegalModalityModifiers(property);
345 }
346 checkPropertyInitializer(property, propertyDescriptor);
347 checkAccessors(property, propertyDescriptor);
348 checkDeclaredTypeInPublicMember(property, propertyDescriptor);
349 }
350
351 private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) {
352 boolean hasDeferredType;
353 if (member instanceof JetProperty) {
354 hasDeferredType = ((JetProperty) member).getTypeRef() == null && DescriptorResolver.hasBody((JetProperty) member);
355 }
356 else {
357 assert member instanceof JetFunction;
358 JetFunction function = (JetFunction) member;
359 hasDeferredType = function.getReturnTypeRef() == null && function.getBodyExpression() != null && !function.hasBlockBody();
360 }
361 if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) {
362 trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member));
363 }
364 }
365
366 private void checkPropertyAbstractness(
367 @NotNull JetProperty property,
368 @NotNull PropertyDescriptor propertyDescriptor,
369 @NotNull ClassDescriptor classDescriptor
370 ) {
371 JetPropertyAccessor getter = property.getGetter();
372 JetPropertyAccessor setter = property.getSetter();
373 JetModifierList modifierList = property.getModifierList();
374 ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
375
376 if (abstractNode != null) { //has abstract modifier
377 if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
378 String name = property.getName();
379 trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor));
380 return;
381 }
382 if (classDescriptor.getKind() == ClassKind.TRAIT) {
383 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property));
384 }
385 }
386
387 if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
388 JetType returnType = propertyDescriptor.getReturnType();
389 if (returnType instanceof DeferredType) {
390 returnType = ((DeferredType) returnType).getDelegate();
391 }
392
393 JetExpression initializer = property.getInitializer();
394 if (initializer != null) {
395 trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
396 }
397 JetPropertyDelegate delegate = property.getDelegate();
398 if (delegate != null) {
399 trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
400 }
401 if (getter != null && getter.getBodyExpression() != null) {
402 trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
403 }
404 if (setter != null && setter.getBodyExpression() != null) {
405 trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter));
406 }
407 }
408 }
409
410 private void checkPropertyInitializer(
411 @NotNull JetProperty property,
412 @NotNull PropertyDescriptor propertyDescriptor
413 ) {
414 JetPropertyAccessor getter = property.getGetter();
415 JetPropertyAccessor setter = property.getSetter();
416 boolean hasAccessorImplementation = (getter != null && getter.getBodyExpression() != null) ||
417 (setter != null && setter.getBodyExpression() != null);
418
419 if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
420 if (property.getDelegateExpressionOrInitializer() == null && property.getTypeRef() == null) {
421 trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
422 }
423 return;
424 }
425 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
426 boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.TRAIT;
427 JetExpression initializer = property.getInitializer();
428 JetPropertyDelegate delegate = property.getDelegate();
429 boolean backingFieldRequired = trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
430
431 if (inTrait && backingFieldRequired && hasAccessorImplementation) {
432 trace.report(BACKING_FIELD_IN_TRAIT.on(property));
433 }
434 if (initializer == null && delegate == null) {
435 boolean error = false;
436 if (backingFieldRequired && !inTrait && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) {
437 if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
438 error = true;
439 trace.report(MUST_BE_INITIALIZED.on(property));
440 }
441 else {
442 error = true;
443 trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property));
444 }
445 }
446 if (!error && property.getTypeRef() == null) {
447 trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
448 }
449 if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) {
450 trace.report(FINAL_PROPERTY_IN_TRAIT.on(property));
451 }
452 return;
453 }
454 if (inTrait) {
455 if (delegate != null) {
456 trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate));
457 }
458 else {
459 trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
460 }
461 }
462 else if (!backingFieldRequired && delegate == null) {
463 trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
464 }
465 }
466
467 protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) {
468 reportErrorIfHasIllegalModifier(function);
469 DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
470 boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD);
471 checkDeclaredTypeInPublicMember(function, functionDescriptor);
472 if (containingDescriptor instanceof ClassDescriptor) {
473 ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
474 boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT;
475 boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS;
476 boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT;
477 if (hasAbstractModifier && !inAbstractClass && !inEnum) {
478 trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor));
479 }
480 if (hasAbstractModifier && inTrait) {
481 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function));
482 }
483 boolean hasBody = function.getBodyExpression() != null;
484 if (hasBody && hasAbstractModifier) {
485 trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor));
486 }
487 if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) {
488 trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
489 }
490 if (!hasBody && !hasAbstractModifier && !inTrait) {
491 trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor));
492 }
493 return;
494 }
495 modifiersChecker.checkIllegalModalityModifiers(function);
496 if (function.getBodyExpression() == null && !hasAbstractModifier) {
497 trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
498 }
499 }
500
501 private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
502 for (JetPropertyAccessor accessor : property.getAccessors()) {
503 modifiersChecker.checkIllegalModalityModifiers(accessor);
504 }
505 JetPropertyAccessor getter = property.getGetter();
506 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
507 JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null;
508 if (getterModifierList != null && getterDescriptor != null) {
509 Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets
510 .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD,
511 JetTokens.INTERNAL_KEYWORD));
512 if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) {
513 for (ASTNode node : nodes.values()) {
514 trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi()));
515 }
516 }
517 else {
518 for (ASTNode node : nodes.values()) {
519 trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi()));
520 }
521 }
522 }
523 }
524
525 private void checkEnumModifiers(JetClass aClass) {
526 if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) {
527 trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass));
528 }
529 }
530
531 private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) {
532 DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration();
533 assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor;
534 ClassDescriptor enumClass = (ClassDescriptor) declaration;
535
536 List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers();
537 ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor();
538 assert constructor != null;
539 if (!constructor.getValueParameters().isEmpty() && delegationSpecifiers.isEmpty()) {
540 trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass));
541 }
542
543 for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
544 JetTypeReference typeReference = delegationSpecifier.getTypeReference();
545 if (typeReference != null) {
546 JetType type = trace.getBindingContext().get(TYPE, typeReference);
547 if (type != null) {
548 JetType enumType = enumClass.getDefaultType();
549 if (!type.getConstructor().equals(enumType.getConstructor())) {
550 trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass));
551 }
552 }
553 }
554 }
555 }
556 }