001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.resolve; 018 019 import com.google.common.collect.Multimap; 020 import com.google.common.collect.Sets; 021 import com.intellij.lang.ASTNode; 022 import com.intellij.psi.PsiElement; 023 import com.intellij.psi.tree.IElementType; 024 import org.jetbrains.annotations.NotNull; 025 import org.jetbrains.annotations.Nullable; 026 import org.jetbrains.kotlin.descriptors.*; 027 import org.jetbrains.kotlin.diagnostics.Errors; 028 import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; 029 import org.jetbrains.kotlin.lexer.JetTokens; 030 import org.jetbrains.kotlin.psi.*; 031 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; 032 import org.jetbrains.kotlin.types.JetType; 033 import org.jetbrains.kotlin.types.SubstitutionUtils; 034 import org.jetbrains.kotlin.types.TypeConstructor; 035 import org.jetbrains.kotlin.types.TypeProjection; 036 import org.jetbrains.kotlin.types.checker.JetTypeChecker; 037 038 import javax.inject.Inject; 039 import java.util.*; 040 041 import static org.jetbrains.kotlin.diagnostics.Errors.*; 042 import static org.jetbrains.kotlin.resolve.BindingContext.TYPE; 043 import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_PARAMETER; 044 import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers; 045 import static org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers; 046 047 public class DeclarationsChecker { 048 private BindingTrace trace; 049 private ModifiersChecker modifiersChecker; 050 private DescriptorResolver descriptorResolver; 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 setModifiersChecker(@NotNull ModifiersChecker modifiersChecker) { 064 this.modifiersChecker = modifiersChecker; 065 } 066 067 public void process(@NotNull BodiesResolveContext bodiesResolveContext) { 068 for (JetFile file : bodiesResolveContext.getFiles()) { 069 checkModifiersAndAnnotationsInPackageDirective(file); 070 } 071 072 Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = bodiesResolveContext.getDeclaredClasses(); 073 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : classes.entrySet()) { 074 JetClassOrObject classOrObject = entry.getKey(); 075 ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue(); 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 } 092 093 Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions(); 094 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) { 095 JetNamedFunction function = entry.getKey(); 096 SimpleFunctionDescriptor functionDescriptor = entry.getValue(); 097 098 checkFunction(function, functionDescriptor); 099 modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor); 100 } 101 102 Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties(); 103 for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) { 104 JetProperty property = entry.getKey(); 105 PropertyDescriptor propertyDescriptor = entry.getValue(); 106 107 checkProperty(property, propertyDescriptor); 108 modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor); 109 } 110 111 for (Map.Entry<JetSecondaryConstructor, ConstructorDescriptor> entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) { 112 ConstructorDescriptor constructorDescriptor = entry.getValue(); 113 JetSecondaryConstructor declaration = entry.getKey(); 114 checkConstructorDeclaration(constructorDescriptor, declaration); 115 } 116 117 } 118 119 private void checkConstructorDeclaration(ConstructorDescriptor constructorDescriptor, JetDeclaration declaration) { 120 modifiersChecker.reportIllegalModalityModifiers(declaration); 121 reportErrorIfHasIllegalModifier(declaration); 122 modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor); 123 } 124 125 private void reportErrorIfHasIllegalModifier(JetModifierListOwner declaration) { 126 if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) { 127 trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration)); 128 } 129 if (declaration.hasModifier(JetTokens.ANNOTATION_KEYWORD)) { 130 trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration)); 131 } 132 } 133 134 private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) { 135 JetPackageDirective packageDirective = file.getPackageDirective(); 136 if (packageDirective == null) return; 137 138 JetModifierList modifierList = packageDirective.getModifierList(); 139 if (modifierList == null) return; 140 141 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) { 142 JetConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression(); 143 if (calleeExpression != null) { 144 JetReferenceExpression reference = calleeExpression.getConstructorReferenceExpression(); 145 if (reference != null) { 146 trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); 147 } 148 } 149 } 150 151 ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace); 152 } 153 154 private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) { 155 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) { 156 checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference()); 157 } 158 159 if (!(classOrObject instanceof JetClass)) return; 160 JetClass jetClass = (JetClass) classOrObject; 161 162 for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) { 163 checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound()); 164 checkFinalUpperBounds(jetTypeParameter.getExtendsBound()); 165 } 166 167 for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) { 168 checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference()); 169 checkFinalUpperBounds(constraint.getBoundTypeReference()); 170 } 171 } 172 173 private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) { 174 if (typeReference != null) { 175 JetType type = trace.getBindingContext().get(TYPE, typeReference); 176 if (type != null) { 177 DescriptorResolver.checkBounds(typeReference, type, trace); 178 } 179 } 180 } 181 182 private void checkFinalUpperBounds(@Nullable JetTypeReference typeReference) { 183 if (typeReference != null) { 184 JetType type = trace.getBindingContext().get(TYPE, typeReference); 185 if (type != null) { 186 DescriptorResolver.checkUpperBoundType(typeReference, type, trace); 187 } 188 } 189 } 190 191 private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) { 192 Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils 193 .buildDeepSubstitutionMultimap(classDescriptor.getDefaultType()); 194 for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) { 195 Collection<TypeProjection> projections = entry.getValue(); 196 if (projections.size() > 1) { 197 TypeConstructor typeConstructor = entry.getKey(); 198 DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); 199 assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor; 200 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; 201 202 // Immediate arguments of supertypes cannot be projected 203 Set<JetType> conflictingTypes = Sets.newLinkedHashSet(); 204 for (TypeProjection projection : projections) { 205 conflictingTypes.add(projection.getType()); 206 } 207 removeDuplicateTypes(conflictingTypes); 208 if (conflictingTypes.size() > 1) { 209 DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); 210 assert containingDeclaration instanceof ClassDescriptor : containingDeclaration; 211 JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor); 212 assert psiElement != null; 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 static void removeDuplicateTypes(Set<JetType> conflictingTypes) { 225 for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) { 226 JetType type = iterator.next(); 227 for (JetType otherType : conflictingTypes) { 228 boolean subtypeOf = JetTypeChecker.DEFAULT.equalTypes(type, otherType); 229 if (type != otherType && subtypeOf) { 230 iterator.remove(); 231 break; 232 } 233 } 234 } 235 } 236 private void checkObject(JetObjectDeclaration declaration, ClassDescriptor classDescriptor) { 237 AnnotationResolver.reportDeprecatedAnnotationSyntax(declaration.getAnnotations(), trace); 238 reportErrorIfHasIllegalModifier(declaration); 239 if (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) { 240 trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor)); 241 } 242 } 243 244 private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) { 245 AnnotationResolver.reportDeprecatedAnnotationSyntax(aClass.getAnnotations(), trace); 246 checkOpenMembers(classDescriptor); 247 checkPrimaryConstructor(aClass, classDescriptor); 248 checkTypeParameters(aClass); 249 250 if (aClass.isInterface()) { 251 ASTNode traitKeyword = aClass.getNode().findChildByType(JetTokens.TRAIT_KEYWORD); 252 if (traitKeyword != null) { 253 trace.report(Errors.DEPRECATED_TRAIT_KEYWORD.on(traitKeyword.getPsi())); 254 } 255 256 checkTraitModifiers(aClass); 257 checkConstructorInTrait(aClass); 258 } 259 else if (aClass.isAnnotation()) { 260 checkAnnotationClassWithBody(aClass); 261 checkValOnAnnotationParameter(aClass); 262 } 263 else if (aClass.isEnum()) { 264 checkEnumModifiers(aClass); 265 if (aClass.isLocal()) { 266 trace.report(LOCAL_ENUM_NOT_ALLOWED.on(aClass, classDescriptor)); 267 } 268 } 269 else if (aClass instanceof JetEnumEntry) { 270 checkEnumEntry((JetEnumEntry) aClass, classDescriptor); 271 } 272 } 273 274 private void checkPrimaryConstructor(JetClass aClass, ClassDescriptor classDescriptor) { 275 ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); 276 JetPrimaryConstructor declaration = aClass.getPrimaryConstructor(); 277 if (primaryConstructor == null || declaration == null) return; 278 279 for (JetParameter parameter : declaration.getValueParameters()) { 280 PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter); 281 if (propertyDescriptor != null) { 282 modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor); 283 } 284 } 285 286 if (declaration.getModifierList() != null && !declaration.hasConstructorKeyword()) { 287 trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList())); 288 } 289 290 checkConstructorDeclaration(primaryConstructor, declaration); 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.reportIllegalModalityModifiers(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.INTERFACE) { 399 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property)); 400 } 401 } 402 403 if (propertyDescriptor.getModality() == Modality.ABSTRACT) { 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.getTypeReference() == 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.INTERFACE; 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.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, 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.getTypeReference() == 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.getReceiverTypeReference() != 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.INTERFACE; 492 if (hasAbstractModifier && !classCanHaveAbstractMembers(classDescriptor)) { 493 trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor)); 494 } 495 if (hasAbstractModifier && inTrait) { 496 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function)); 497 } 498 boolean hasBody = function.hasBody(); 499 if (hasBody && hasAbstractModifier) { 500 trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor)); 501 } 502 if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) { 503 trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor)); 504 } 505 if (!hasBody && !hasAbstractModifier && !inTrait) { 506 trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor)); 507 } 508 return; 509 } 510 modifiersChecker.reportIllegalModalityModifiers(function); 511 if (!function.hasBody() && !hasAbstractModifier) { 512 trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)); 513 } 514 } 515 516 private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { 517 for (JetPropertyAccessor accessor : property.getAccessors()) { 518 PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); 519 assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText(); 520 modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor); 521 modifiersChecker.reportIllegalModalityModifiers(accessor); 522 } 523 JetPropertyAccessor getter = property.getGetter(); 524 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); 525 JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null; 526 if (getterModifierList != null && getterDescriptor != null) { 527 Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets 528 .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD, 529 JetTokens.INTERNAL_KEYWORD)); 530 if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) { 531 for (ASTNode node : nodes.values()) { 532 trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi())); 533 } 534 } 535 else { 536 for (ASTNode node : nodes.values()) { 537 trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi())); 538 } 539 } 540 } 541 } 542 543 private void checkEnumModifiers(JetClass aClass) { 544 if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) { 545 trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass)); 546 } 547 if (aClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { 548 trace.report(ABSTRACT_MODIFIER_IN_ENUM.on(aClass)); 549 } 550 } 551 552 // Temporary 553 // Returns true if deprecated constructor is in use, like 554 // ENTRY: Enum(arguments) instead of 555 // ENTRY(arguments) 556 public static boolean enumEntryUsesDeprecatedSuperConstructor(@NotNull JetEnumEntry enumEntry) { 557 JetInitializerList initializerList = enumEntry.getInitializerList(); 558 if (initializerList == null) return false; 559 JetTypeReference typeReference = initializerList.getInitializers().get(0).getTypeReference(); 560 if (typeReference == null) return false; 561 JetUserType userType = (JetUserType) typeReference.getTypeElement(); 562 if (userType == null || userType.getReferenceExpression() instanceof JetEnumEntrySuperclassReferenceExpression) return false; 563 return true; 564 } 565 566 // Temporary 567 // Returns comma if it's an enum entry without following comma (entry is not last in enum), 568 // or semicolon if it's an enum entry without following semicolon, may be after comma (entry is last in enum), 569 // or empty string if an enum entry has the necessary following delimiter 570 @NotNull 571 private static String enumEntryExpectedDelimiter(@NotNull JetEnumEntry enumEntry) { 572 PsiElement next = enumEntry.getNextSibling(); 573 while (next != null) { 574 if (next instanceof JetDeclaration) break; 575 next = next.getNextSibling(); 576 } 577 JetDeclaration nextDeclaration = (JetDeclaration) next; 578 next = PsiUtilPackage.getNextSiblingIgnoringWhitespaceAndComments(enumEntry); 579 IElementType nextType = next != null ? next.getNode().getElementType() : null; 580 if (nextDeclaration instanceof JetEnumEntry) { 581 // Not last 582 return nextType != JetTokens.COMMA ? "," : ""; 583 } 584 else { 585 // Last: after it we can have semicolon, just closing brace, or comma followed by semicolon / closing brace 586 if (nextType == JetTokens.COMMA) { 587 next = PsiUtilPackage.getNextSiblingIgnoringWhitespaceAndComments(next); 588 nextType = next != null ? next.getNode().getElementType() : null; 589 } 590 return nextType != JetTokens.SEMICOLON && nextType != JetTokens.RBRACE ? ";" : ""; 591 } 592 } 593 594 public static boolean enumEntryUsesDeprecatedOrNoDelimiter(@NotNull JetEnumEntry enumEntry) { 595 return !enumEntryExpectedDelimiter(enumEntry).isEmpty(); 596 } 597 598 static public boolean enumEntryAfterEnumMember(@NotNull JetEnumEntry enumEntry) { 599 PsiElement previous = enumEntry.getPrevSibling(); 600 while (previous != null) { 601 if (previous instanceof JetEnumEntry) return false; 602 if (previous instanceof JetDeclaration) return true; 603 previous = previous.getPrevSibling(); 604 } 605 return false; 606 } 607 608 private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) { 609 DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration(); 610 assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor; 611 ClassDescriptor enumClass = (ClassDescriptor) declaration; 612 613 if (enumEntryUsesDeprecatedSuperConstructor(enumEntry)) { 614 trace.report(Errors.ENUM_ENTRY_USES_DEPRECATED_SUPER_CONSTRUCTOR.on(enumEntry, classDescriptor)); 615 } 616 String neededDelimiter = enumEntryExpectedDelimiter(enumEntry); 617 if (!neededDelimiter.isEmpty()) { 618 trace.report(Errors.ENUM_ENTRY_USES_DEPRECATED_OR_NO_DELIMITER.on(enumEntry, classDescriptor, neededDelimiter)); 619 } 620 if (enumEntryAfterEnumMember(enumEntry)) { 621 trace.report(Errors.ENUM_ENTRY_AFTER_ENUM_MEMBER.on(enumEntry, classDescriptor)); 622 } 623 624 List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers(); 625 ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor(); 626 if ((constructor == null || !constructor.getValueParameters().isEmpty()) && delegationSpecifiers.isEmpty()) { 627 trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass)); 628 } 629 630 for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { 631 JetTypeReference typeReference = delegationSpecifier.getTypeReference(); 632 if (typeReference != null) { 633 JetType type = trace.getBindingContext().get(TYPE, typeReference); 634 if (type != null) { 635 JetType enumType = enumClass.getDefaultType(); 636 if (!type.getConstructor().equals(enumType.getConstructor())) { 637 trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass)); 638 } 639 } 640 } 641 } 642 } 643 }