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 017package org.jetbrains.jet.lang.resolve; 018 019import com.google.common.collect.Sets; 020import com.intellij.lang.ASTNode; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.jet.lang.descriptors.*; 023import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; 024import org.jetbrains.jet.lang.diagnostics.Errors; 025import org.jetbrains.jet.lang.psi.*; 026import org.jetbrains.jet.lang.types.DeferredType; 027import org.jetbrains.jet.lang.types.JetType; 028import org.jetbrains.jet.lexer.JetKeywordToken; 029import org.jetbrains.jet.lexer.JetTokens; 030 031import javax.inject.Inject; 032import java.util.List; 033import java.util.Map; 034 035import static org.jetbrains.jet.lang.diagnostics.Errors.*; 036import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE; 037 038public class DeclarationsChecker { 039 @NotNull 040 private BindingTrace trace; 041 @NotNull 042 private ModifiersChecker modifiersChecker; 043 044 @Inject 045 public void setTrace(@NotNull BindingTrace trace) { 046 this.trace = trace; 047 this.modifiersChecker = new ModifiersChecker(trace); 048 } 049 050 public void process(@NotNull BodiesResolveContext bodiesResolveContext) { 051 Map<JetClass, MutableClassDescriptor> classes = bodiesResolveContext.getClasses(); 052 for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) { 053 JetClass aClass = entry.getKey(); 054 MutableClassDescriptor classDescriptor = entry.getValue(); 055 if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue; 056 057 checkClass(aClass, classDescriptor); 058 modifiersChecker.checkModifiersForDeclaration(aClass, classDescriptor); 059 } 060 061 Map<JetObjectDeclaration, MutableClassDescriptor> objects = bodiesResolveContext.getObjects(); 062 for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : objects.entrySet()) { 063 JetObjectDeclaration objectDeclaration = entry.getKey(); 064 MutableClassDescriptor objectDescriptor = entry.getValue(); 065 066 if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue; 067 checkObject(objectDeclaration); 068 modifiersChecker.checkModifiersForDeclaration(objectDeclaration, objectDescriptor); 069 } 070 071 Map<JetNamedFunction, SimpleFunctionDescriptor> functions = bodiesResolveContext.getFunctions(); 072 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : functions.entrySet()) { 073 JetNamedFunction function = entry.getKey(); 074 SimpleFunctionDescriptor functionDescriptor = entry.getValue(); 075 076 if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue; 077 checkFunction(function, functionDescriptor); 078 modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor); 079 } 080 081 Map<JetProperty, PropertyDescriptor> properties = bodiesResolveContext.getProperties(); 082 for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) { 083 JetProperty property = entry.getKey(); 084 PropertyDescriptor propertyDescriptor = entry.getValue(); 085 086 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue; 087 checkProperty(property, propertyDescriptor); 088 modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor); 089 } 090 091 } 092 093 private void reportErrorIfHasEnumModifier(JetModifierListOwner declaration) { 094 if (declaration.hasModifier(JetTokens.ENUM_KEYWORD)) { 095 trace.report(ILLEGAL_ENUM_ANNOTATION.on(declaration)); 096 } 097 } 098 099 private void checkObject(JetObjectDeclaration declaration) { 100 reportErrorIfHasEnumModifier(declaration); 101 } 102 103 private void checkClass(JetClass aClass, MutableClassDescriptor classDescriptor) { 104 checkOpenMembers(classDescriptor); 105 if (aClass.isTrait()) { 106 checkTraitModifiers(aClass); 107 } 108 else if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) { 109 checkEnumModifiers(aClass); 110 } 111 else if (classDescriptor.getKind() == ClassKind.ENUM_ENTRY) { 112 checkEnumEntry(aClass, classDescriptor); 113 } 114 } 115 116 private void checkTraitModifiers(JetClass aClass) { 117 reportErrorIfHasEnumModifier(aClass); 118 JetModifierList modifierList = aClass.getModifierList(); 119 if (modifierList == null) return; 120 if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) { 121 trace.report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(modifierList.getModifierNode(JetTokens.FINAL_KEYWORD).getPsi())); 122 } 123 if (modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { 124 trace.report(Errors.ABSTRACT_MODIFIER_IN_TRAIT.on(aClass)); 125 } 126 if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) { 127 trace.report(Errors.OPEN_MODIFIER_IN_TRAIT.on(aClass)); 128 } 129 } 130 131 132 private void checkOpenMembers(MutableClassDescriptor classDescriptor) { 133 for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) { 134 if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue; 135 JetNamedDeclaration member = (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), memberDescriptor); 136 if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) { 137 trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member)); 138 } 139 } 140 } 141 142 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { 143 reportErrorIfHasEnumModifier(property); 144 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); 145 if (containingDeclaration instanceof ClassDescriptor) { 146 checkPropertyAbstractness(property, propertyDescriptor, (ClassDescriptor) containingDeclaration); 147 } 148 else { 149 modifiersChecker.checkIllegalModalityModifiers(property); 150 } 151 checkPropertyInitializer(property, propertyDescriptor); 152 checkAccessors(property, propertyDescriptor); 153 checkDeclaredTypeInPublicMember(property, propertyDescriptor); 154 } 155 156 private void checkDeclaredTypeInPublicMember(JetNamedDeclaration member, CallableMemberDescriptor memberDescriptor) { 157 boolean hasDeferredType; 158 if (member instanceof JetProperty) { 159 hasDeferredType = ((JetProperty) member).getTypeRef() == null && DescriptorResolver.hasBody((JetProperty) member); 160 } 161 else { 162 assert member instanceof JetFunction; 163 JetFunction function = (JetFunction) member; 164 hasDeferredType = function.getReturnTypeRef() == null && function.getBodyExpression() != null && !function.hasBlockBody(); 165 } 166 if ((memberDescriptor.getVisibility().isPublicAPI()) && memberDescriptor.getOverriddenDescriptors().size() == 0 && hasDeferredType) { 167 trace.report(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE.on(member)); 168 } 169 } 170 171 private void checkPropertyAbstractness( 172 @NotNull JetProperty property, 173 @NotNull PropertyDescriptor propertyDescriptor, 174 @NotNull ClassDescriptor classDescriptor 175 ) { 176 JetPropertyAccessor getter = property.getGetter(); 177 JetPropertyAccessor setter = property.getSetter(); 178 JetModifierList modifierList = property.getModifierList(); 179 ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; 180 181 if (abstractNode != null) { //has abstract modifier 182 if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) { 183 String name = property.getName(); 184 trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, name != null ? name : "", classDescriptor)); 185 return; 186 } 187 if (classDescriptor.getKind() == ClassKind.TRAIT) { 188 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property)); 189 } 190 } 191 192 if (propertyDescriptor.getModality() == Modality.ABSTRACT) { 193 JetType returnType = propertyDescriptor.getReturnType(); 194 if (returnType instanceof DeferredType) { 195 returnType = ((DeferredType) returnType).getActualType(); 196 } 197 198 JetExpression initializer = property.getInitializer(); 199 if (initializer != null) { 200 trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer)); 201 } 202 JetPropertyDelegate delegate = property.getDelegate(); 203 if (delegate != null) { 204 trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate)); 205 } 206 if (getter != null && getter.getBodyExpression() != null) { 207 trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter)); 208 } 209 if (setter != null && setter.getBodyExpression() != null) { 210 trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter)); 211 } 212 } 213 } 214 215 private void checkPropertyInitializer( 216 @NotNull JetProperty property, 217 @NotNull PropertyDescriptor propertyDescriptor 218 ) { 219 JetPropertyAccessor getter = property.getGetter(); 220 JetPropertyAccessor setter = property.getSetter(); 221 boolean hasAccessorImplementation = (getter != null && getter.getBodyExpression() != null) || 222 (setter != null && setter.getBodyExpression() != null); 223 224 if (propertyDescriptor.getModality() == Modality.ABSTRACT) { 225 if (property.getDelegateExpressionOrInitializer() == null && property.getTypeRef() == null) { 226 trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property)); 227 } 228 return; 229 } 230 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); 231 boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.TRAIT; 232 JetExpression initializer = property.getInitializer(); 233 JetPropertyDelegate delegate = property.getDelegate(); 234 boolean backingFieldRequired = trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); 235 236 if (inTrait && backingFieldRequired && hasAccessorImplementation) { 237 trace.report(BACKING_FIELD_IN_TRAIT.on(property)); 238 } 239 if (initializer == null && delegate == null) { 240 boolean error = false; 241 if (backingFieldRequired && !inTrait && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { 242 if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) { 243 error = true; 244 trace.report(MUST_BE_INITIALIZED.on(property)); 245 } 246 else { 247 error = true; 248 trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property)); 249 } 250 } 251 if (!error && property.getTypeRef() == null) { 252 trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property)); 253 } 254 if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) { 255 trace.report(FINAL_PROPERTY_IN_TRAIT.on(property)); 256 } 257 return; 258 } 259 if (inTrait) { 260 if (delegate != null) { 261 trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate)); 262 } 263 else { 264 trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer)); 265 } 266 } 267 else if (!backingFieldRequired && delegate == null) { 268 trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer)); 269 } 270 } 271 272 protected void checkFunction(JetNamedFunction function, SimpleFunctionDescriptor functionDescriptor) { 273 reportErrorIfHasEnumModifier(function); 274 DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration(); 275 boolean hasAbstractModifier = function.hasModifier(JetTokens.ABSTRACT_KEYWORD); 276 checkDeclaredTypeInPublicMember(function, functionDescriptor); 277 if (containingDescriptor instanceof ClassDescriptor) { 278 ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; 279 boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT; 280 boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS; 281 boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT; 282 if (hasAbstractModifier && !inAbstractClass && !inEnum) { 283 trace.report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(function, functionDescriptor.getName().asString(), classDescriptor)); 284 } 285 if (hasAbstractModifier && inTrait) { 286 trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(function)); 287 } 288 boolean hasBody = function.getBodyExpression() != null; 289 if (hasBody && hasAbstractModifier) { 290 trace.report(ABSTRACT_FUNCTION_WITH_BODY.on(function, functionDescriptor)); 291 } 292 if (!hasBody && function.hasModifier(JetTokens.FINAL_KEYWORD) && inTrait) { 293 trace.report(FINAL_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor)); 294 } 295 if (!hasBody && !hasAbstractModifier && !inTrait) { 296 trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor)); 297 } 298 return; 299 } 300 modifiersChecker.checkIllegalModalityModifiers(function); 301 if (function.getBodyExpression() == null && !hasAbstractModifier) { 302 trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)); 303 } 304 } 305 306 private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { 307 for (JetPropertyAccessor accessor : property.getAccessors()) { 308 modifiersChecker.checkIllegalModalityModifiers(accessor); 309 } 310 JetPropertyAccessor getter = property.getGetter(); 311 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); 312 JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null; 313 if (getterModifierList != null && getterDescriptor != null) { 314 Map<JetKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers(getterModifierList, Sets 315 .newHashSet(JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD, 316 JetTokens.INTERNAL_KEYWORD)); 317 if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) { 318 for (ASTNode node : nodes.values()) { 319 trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi())); 320 } 321 } 322 else { 323 for (ASTNode node : nodes.values()) { 324 trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi())); 325 } 326 } 327 } 328 } 329 330 private void checkEnumModifiers(JetClass aClass) { 331 if (aClass.hasModifier(JetTokens.OPEN_KEYWORD)) { 332 trace.report(OPEN_MODIFIER_IN_ENUM.on(aClass)); 333 } 334 } 335 336 private void checkEnumEntry(JetClass aClass, ClassDescriptor classDescriptor) { 337 DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration().getContainingDeclaration(); 338 assert declaration instanceof ClassDescriptor; 339 ClassDescriptor enumClass = (ClassDescriptor) declaration; 340 assert enumClass.getKind() == ClassKind.ENUM_CLASS; 341 342 List<JetDelegationSpecifier> delegationSpecifiers = aClass.getDelegationSpecifiers(); 343 ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor(); 344 assert constructor != null; 345 if (!constructor.getValueParameters().isEmpty() && delegationSpecifiers.isEmpty()) { 346 trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(aClass, enumClass)); 347 } 348 349 for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { 350 JetTypeReference typeReference = delegationSpecifier.getTypeReference(); 351 if (typeReference != null) { 352 JetType type = trace.getBindingContext().get(TYPE, typeReference); 353 if (type != null) { 354 JetType enumType = enumClass.getDefaultType(); 355 if (!type.getConstructor().equals(enumType.getConstructor())) { 356 trace.report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass)); 357 } 358 } 359 } 360 } 361 } 362}