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 }