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