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 checkPrimaryConstructor(classOrObject, classDescriptor); 091 092 modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor); 093 } 094 095 Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions(); 096 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) { 097 JetNamedFunction function = entry.getKey(); 098 SimpleFunctionDescriptor functionDescriptor = entry.getValue(); 099 100 checkFunction(function, functionDescriptor); 101 modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor); 102 } 103 104 Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties(); 105 for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) { 106 JetProperty property = entry.getKey(); 107 PropertyDescriptor propertyDescriptor = entry.getValue(); 108 109 checkProperty(property, propertyDescriptor); 110 modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor); 111 } 112 113 for (Map.Entry<JetSecondaryConstructor, ConstructorDescriptor> entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) { 114 ConstructorDescriptor constructorDescriptor = entry.getValue(); 115 JetSecondaryConstructor declaration = entry.getKey(); 116 checkConstructorDeclaration(constructorDescriptor, declaration); 117 } 118 119 } 120 121 private void checkConstructorDeclaration(ConstructorDescriptor constructorDescriptor, JetDeclaration declaration) { 122 modifiersChecker.reportIllegalModalityModifiers(declaration); 123 reportErrorIfHasIllegalModifier(declaration); 124 modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor); 125 } 126 127 private void reportErrorIfHasIllegalModifier(JetModifierListOwner declaration) { 128 if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) { 129 trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration)); 130 } 131 if (declaration.hasModifier(JetTokens.ANNOTATION_KEYWORD)) { 132 trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration)); 133 } 134 } 135 136 private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) { 137 JetPackageDirective packageDirective = file.getPackageDirective(); 138 if (packageDirective == null) return; 139 140 JetModifierList modifierList = packageDirective.getModifierList(); 141 if (modifierList == null) return; 142 143 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) { 144 JetConstructorCalleeExpression calleeExpression = annotationEntry.getCalleeExpression(); 145 if (calleeExpression != null) { 146 JetReferenceExpression reference = calleeExpression.getConstructorReferenceExpression(); 147 if (reference != null) { 148 trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); 149 } 150 } 151 } 152 153 ModifiersChecker.reportIllegalModifiers(modifierList, Arrays.asList(JetTokens.MODIFIER_KEYWORDS_ARRAY), trace); 154 } 155 156 private void checkTypesInClassHeader(@NotNull JetClassOrObject classOrObject) { 157 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) { 158 checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference()); 159 } 160 161 if (!(classOrObject instanceof JetClass)) return; 162 JetClass jetClass = (JetClass) classOrObject; 163 164 for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) { 165 checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound()); 166 checkFinalUpperBounds(jetTypeParameter.getExtendsBound()); 167 } 168 169 for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) { 170 checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference()); 171 checkFinalUpperBounds(constraint.getBoundTypeReference()); 172 } 173 } 174 175 private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) { 176 if (typeReference != null) { 177 JetType type = trace.getBindingContext().get(TYPE, typeReference); 178 if (type != null) { 179 DescriptorResolver.checkBounds(typeReference, type, trace); 180 } 181 } 182 } 183 184 private void checkFinalUpperBounds(@Nullable JetTypeReference typeReference) { 185 if (typeReference != null) { 186 JetType type = trace.getBindingContext().get(TYPE, typeReference); 187 if (type != null) { 188 DescriptorResolver.checkUpperBoundType(typeReference, type, trace); 189 } 190 } 191 } 192 193 private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) { 194 Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils 195 .buildDeepSubstitutionMultimap(classDescriptor.getDefaultType()); 196 for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) { 197 Collection<TypeProjection> projections = entry.getValue(); 198 if (projections.size() > 1) { 199 TypeConstructor typeConstructor = entry.getKey(); 200 DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); 201 assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor; 202 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; 203 204 // Immediate arguments of supertypes cannot be projected 205 Set<JetType> conflictingTypes = Sets.newLinkedHashSet(); 206 for (TypeProjection projection : projections) { 207 conflictingTypes.add(projection.getType()); 208 } 209 removeDuplicateTypes(conflictingTypes); 210 if (conflictingTypes.size() > 1) { 211 DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); 212 assert containingDeclaration instanceof ClassDescriptor : containingDeclaration; 213 JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor); 214 assert psiElement != null; 215 JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList(); 216 assert delegationSpecifierList != null; 217 // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes); 218 trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES 219 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration, 220 conflictingTypes)); 221 } 222 } 223 } 224 } 225 226 private static void removeDuplicateTypes(Set<JetType> conflictingTypes) { 227 for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) { 228 JetType type = iterator.next(); 229 for (JetType otherType : conflictingTypes) { 230 boolean subtypeOf = JetTypeChecker.DEFAULT.equalTypes(type, otherType); 231 if (type != otherType && subtypeOf) { 232 iterator.remove(); 233 break; 234 } 235 } 236 } 237 } 238 private void checkObject(JetObjectDeclaration declaration, ClassDescriptor classDescriptor) { 239 AnnotationResolver.reportDeprecatedAnnotationSyntax(declaration.getAnnotations(), trace); 240 reportErrorIfHasIllegalModifier(declaration); 241 if (declaration.isLocal() && !declaration.isCompanion() && !declaration.isObjectLiteral()) { 242 trace.report(LOCAL_OBJECT_NOT_ALLOWED.on(declaration, classDescriptor)); 243 } 244 } 245 246 private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) { 247 AnnotationResolver.reportDeprecatedAnnotationSyntax(aClass.getAnnotations(), trace); 248 checkOpenMembers(classDescriptor); 249 checkTypeParameters(aClass); 250 251 if (aClass.isInterface()) { 252 ASTNode traitKeyword = aClass.getNode().findChildByType(JetTokens.TRAIT_KEYWORD); 253 if (traitKeyword != null) { 254 trace.report(Errors.DEPRECATED_TRAIT_KEYWORD.on(traitKeyword.getPsi())); 255 } 256 257 checkTraitModifiers(aClass); 258 checkConstructorInTrait(aClass); 259 } 260 else if (aClass.isAnnotation()) { 261 checkAnnotationClassWithBody(aClass); 262 checkValOnAnnotationParameter(aClass); 263 } 264 else if (aClass.isEnum()) { 265 checkEnumModifiers(aClass); 266 if (aClass.isLocal()) { 267 trace.report(LOCAL_ENUM_NOT_ALLOWED.on(aClass, classDescriptor)); 268 } 269 } 270 else if (aClass instanceof JetEnumEntry) { 271 checkEnumEntry((JetEnumEntry) aClass, classDescriptor); 272 } 273 } 274 275 private void checkPrimaryConstructor(JetClassOrObject classOrObject, ClassDescriptor classDescriptor) { 276 ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); 277 JetPrimaryConstructor declaration = classOrObject.getPrimaryConstructor(); 278 if (primaryConstructor == null || declaration == null) return; 279 280 for (JetParameter parameter : declaration.getValueParameters()) { 281 PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter); 282 if (propertyDescriptor != null) { 283 modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor); 284 } 285 } 286 287 if (declaration.getModifierList() != null && !declaration.hasConstructorKeyword()) { 288 trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList())); 289 } 290 291 if (!(classOrObject instanceof JetClass)) { 292 trace.report(CONSTRUCTOR_IN_OBJECT.on(declaration)); 293 } 294 295 checkConstructorDeclaration(primaryConstructor, declaration); 296 } 297 298 private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) { 299 // TODO: Support annotation for type parameters 300 for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) { 301 AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(jetTypeParameter, trace); 302 303 TypeParameterDescriptor typeParameter = trace.get(TYPE_PARAMETER, jetTypeParameter); 304 if (typeParameter != null) { 305 DescriptorResolver.checkConflictingUpperBounds(trace, typeParameter, jetTypeParameter); 306 } 307 } 308 } 309 310 private void checkConstructorInTrait(JetClass klass) { 311 JetPrimaryConstructor primaryConstructor = klass.getPrimaryConstructor(); 312 if (primaryConstructor != null) { 313 trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructor)); 314 } 315 } 316 317 private void checkTraitModifiers(JetClass aClass) { 318 reportErrorIfHasIllegalModifier(aClass); 319 JetModifierList modifierList = aClass.getModifierList(); 320 if (modifierList == null) return; 321 if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) { 322 trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(aClass)); 323 } 324 if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { 325 trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass)); 326 } 327 if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) { 328 trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass)); 329 } 330 } 331 332 private void checkAnnotationClassWithBody(JetClassOrObject classOrObject) { 333 if (classOrObject.getBody() != null) { 334 trace.report(ANNOTATION_CLASS_WITH_BODY.on(classOrObject.getBody())); 335 } 336 } 337 338 private void checkValOnAnnotationParameter(JetClass aClass) { 339 for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) { 340 if (!parameter.hasValOrVarNode()) { 341 trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter)); 342 } 343 } 344 } 345 346 private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) { 347 if (classCanHaveOpenMembers(classDescriptor)) return; 348 349 for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) { 350 if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue; 351 JetNamedDeclaration member = (JetNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor); 352 if (member != null && member.hasModifier(JetTokens.OPEN_KEYWORD)) { 353 trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member)); 354 } 355 } 356 } 357 358 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { 359 reportErrorIfHasIllegalModifier(property); 360 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); 361 if (containingDeclaration instanceof ClassDescriptor) { 362 checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration); 363 } 364 else { 365 modifiersChecker.reportIllegalModalityModifiers(property); 366 } 367 checkPropertyInitializer(property, propertyDescriptor); 368 checkAccessors(property, propertyDescriptor); 369 checkDeclaredTypeInPublicMember(property, propertyDescriptor); 370 } 371 372 private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) { 373 boolean hasDeferredType; 374 if (member instanceof JetProperty) { 375 hasDeferredType = ((JetProperty) member).getTypeReference() == null && DescriptorResolver.hasBody((JetProperty) member); 376 } 377 else { 378 assert member instanceof JetFunction; 379 JetFunction function = (JetFunction) member; 380 hasDeferredType = function.getTypeReference() == null && function.hasBody() && !function.hasBlockBody(); 381 } 382 if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) { 383 trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member)); 384 } 385 } 386 387 private void checkPropertyAbstractness( 388 @NotNull JetProperty property, 389 @NotNull PropertyDescriptor propertyDescriptor, 390 @NotNull ClassDescriptor classDescriptor 391 ) { 392 JetPropertyAccessor getter = property.getGetter(); 393 JetPropertyAccessor setter = property.getSetter(); 394 JetModifierList modifierList = property.getModifierList(); 395 ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; 396 397 if (abstractNode != null) { //has abstract modifier 398 if (!classCanHaveAbstractMembers(classDescriptor)) { 399 String name = property.getName(); 400 trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor)); 401 return; 402 } 403 if (classDescriptor.getKind() == ClassKind.INTERFACE) { 404 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property)); 405 } 406 } 407 408 if (propertyDescriptor.getModality() == Modality.ABSTRACT) { 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.INTERFACE; 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.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, 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.INTERFACE; 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.reportIllegalModalityModifiers(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 PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); 524 assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText(); 525 modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor); 526 modifiersChecker.reportIllegalModalityModifiers(accessor); 527 } 528 JetPropertyAccessor getter = property.getGetter(); 529 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); 530 JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null; 531 if (getterModifierList != null && getterDescriptor != null) { 532 Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets 533 .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD, 534 JetTokens.INTERNAL_KEYWORD)); 535 if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) { 536 for (ASTNode node : nodes.values()) { 537 trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi())); 538 } 539 } 540 else { 541 for (ASTNode node : nodes.values()) { 542 trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi())); 543 } 544 } 545 } 546 } 547 548 private void checkEnumModifiers(JetClass aClass) { 549 if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) { 550 trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass)); 551 } 552 if (aClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { 553 trace.report(ABSTRACT_MODIFIER_IN_ENUM.on(aClass)); 554 } 555 } 556 557 // Temporary 558 // Returns true if deprecated constructor is in use, like 559 // ENTRY: Enum(arguments) instead of 560 // ENTRY(arguments) 561 public static boolean enumEntryUsesDeprecatedSuperConstructor(@NotNull JetEnumEntry enumEntry) { 562 JetInitializerList initializerList = enumEntry.getInitializerList(); 563 if (initializerList == null) return false; 564 JetTypeReference typeReference = initializerList.getInitializers().get(0).getTypeReference(); 565 if (typeReference == null) return false; 566 JetUserType userType = (JetUserType) typeReference.getTypeElement(); 567 if (userType == null || userType.getReferenceExpression() instanceof JetEnumEntrySuperclassReferenceExpression) return false; 568 return true; 569 } 570 571 // Temporary 572 // Returns comma if it's an enum entry without following comma (entry is not last in enum), 573 // or semicolon if it's an enum entry without following semicolon, may be after comma (entry is last in enum), 574 // or empty string if an enum entry has the necessary following delimiter 575 @NotNull 576 private static String enumEntryExpectedDelimiter(@NotNull JetEnumEntry enumEntry) { 577 PsiElement next = enumEntry.getNextSibling(); 578 while (next != null) { 579 if (next instanceof JetDeclaration) break; 580 next = next.getNextSibling(); 581 } 582 JetDeclaration nextDeclaration = (JetDeclaration) next; 583 next = PsiUtilPackage.getNextSiblingIgnoringWhitespaceAndComments(enumEntry); 584 IElementType nextType = next != null ? next.getNode().getElementType() : null; 585 if (nextDeclaration instanceof JetEnumEntry) { 586 // Not last 587 return nextType != JetTokens.COMMA ? "," : ""; 588 } 589 else { 590 // Last: after it we can have semicolon, just closing brace, or comma followed by semicolon / closing brace 591 if (nextType == JetTokens.COMMA) { 592 next = PsiUtilPackage.getNextSiblingIgnoringWhitespaceAndComments(next); 593 nextType = next != null ? next.getNode().getElementType() : null; 594 } 595 return nextType != JetTokens.SEMICOLON && nextType != JetTokens.RBRACE ? ";" : ""; 596 } 597 } 598 599 public static boolean enumEntryUsesDeprecatedOrNoDelimiter(@NotNull JetEnumEntry enumEntry) { 600 return !enumEntryExpectedDelimiter(enumEntry).isEmpty(); 601 } 602 603 static public boolean enumEntryAfterEnumMember(@NotNull JetEnumEntry enumEntry) { 604 PsiElement previous = enumEntry.getPrevSibling(); 605 while (previous != null) { 606 if (previous instanceof JetEnumEntry) return false; 607 if (previous instanceof JetDeclaration) return true; 608 previous = previous.getPrevSibling(); 609 } 610 return false; 611 } 612 613 private void checkEnumEntry(@NotNull JetEnumEntry enumEntry, @NotNull ClassDescriptor classDescriptor) { 614 DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration(); 615 assert DescriptorUtils.isEnumClass(declaration) : "Enum entry should be declared in enum class: " + classDescriptor; 616 ClassDescriptor enumClass = (ClassDescriptor) declaration; 617 618 if (enumEntryUsesDeprecatedSuperConstructor(enumEntry)) { 619 trace.report(Errors.ENUM_ENTRY_USES_DEPRECATED_SUPER_CONSTRUCTOR.on(enumEntry, classDescriptor)); 620 } 621 String neededDelimiter = enumEntryExpectedDelimiter(enumEntry); 622 if (!neededDelimiter.isEmpty()) { 623 trace.report(Errors.ENUM_ENTRY_USES_DEPRECATED_OR_NO_DELIMITER.on(enumEntry, classDescriptor, neededDelimiter)); 624 } 625 if (enumEntryAfterEnumMember(enumEntry)) { 626 trace.report(Errors.ENUM_ENTRY_AFTER_ENUM_MEMBER.on(enumEntry, classDescriptor)); 627 } 628 629 List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers(); 630 ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor(); 631 if ((constructor == null || !constructor.getValueParameters().isEmpty()) && delegationSpecifiers.isEmpty()) { 632 trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry, enumClass)); 633 } 634 635 for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { 636 JetTypeReference typeReference = delegationSpecifier.getTypeReference(); 637 if (typeReference != null) { 638 JetType type = trace.getBindingContext().get(TYPE, typeReference); 639 if (type != null) { 640 JetType enumType = enumClass.getDefaultType(); 641 if (!type.getConstructor().equals(enumType.getConstructor())) { 642 trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass)); 643 } 644 } 645 } 646 } 647 } 648 }