1 12 package org.eclipse.jdt.internal.compiler.ast; 13 14 import org.eclipse.jdt.internal.compiler.ASTVisitor; 15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 16 import org.eclipse.jdt.internal.compiler.codegen.*; 17 import org.eclipse.jdt.internal.compiler.flow.*; 18 import org.eclipse.jdt.internal.compiler.impl.Constant; 19 import org.eclipse.jdt.internal.compiler.lookup.*; 20 21 public class Assignment extends Expression { 22 23 public Expression lhs; 24 public Expression expression; 25 26 public Assignment(Expression lhs, Expression expression, int sourceEnd) { 27 this.lhs = lhs; 30 lhs.bits |= IsStrictlyAssigned; this.expression = expression; 32 this.sourceStart = lhs.sourceStart; 33 this.sourceEnd = sourceEnd; 34 } 35 36 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { 37 LocalVariableBinding local = this.lhs.localVariableBinding(); 41 int nullStatus = this.expression.nullStatus(flowInfo); 42 if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { 43 if (nullStatus == FlowInfo.NULL) { 44 flowContext.recordUsingNullReference(currentScope, local, this.lhs, 45 FlowContext.CAN_ONLY_NULL | FlowContext.IN_ASSIGNMENT, flowInfo); 46 } 47 } 48 flowInfo = ((Reference) lhs) 49 .analyseAssignment(currentScope, flowContext, flowInfo, this, false) 50 .unconditionalInits(); 51 if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { 52 switch(nullStatus) { 53 case FlowInfo.NULL : 54 flowInfo.markAsDefinitelyNull(local); 55 break; 56 case FlowInfo.NON_NULL : 57 flowInfo.markAsDefinitelyNonNull(local); 58 break; 59 default: 60 flowInfo.markAsDefinitelyUnknown(local); 61 } 62 if (flowContext.initsOnFinally != null) { 63 switch(nullStatus) { 64 case FlowInfo.NULL : 65 flowContext.initsOnFinally.markAsDefinitelyNull(local); 66 break; 67 case FlowInfo.NON_NULL : 68 flowContext.initsOnFinally.markAsDefinitelyNonNull(local); 69 break; 70 default: 71 flowContext.initsOnFinally.markAsDefinitelyUnknown(local); 72 } 73 } 74 } 75 return flowInfo; 76 } 77 78 void checkAssignment(BlockScope scope, TypeBinding lhsType, TypeBinding rhsType) { 79 FieldBinding leftField = getLastField(this.lhs); 80 if (leftField != null && rhsType != TypeBinding.NULL && lhsType.isWildcard() && ((WildcardBinding)lhsType).boundKind != Wildcard.SUPER) { 81 scope.problemReporter().wildcardAssignment(lhsType, rhsType, this.expression); 82 } else if (leftField != null && !leftField.isStatic() && leftField.declaringClass != null && leftField.declaringClass.isRawType()) { 83 scope.problemReporter().unsafeRawFieldAssignment(leftField, rhsType, this.lhs); 84 } else if (rhsType.needsUncheckedConversion(lhsType)) { 85 scope.problemReporter().unsafeTypeConversion(this.expression, rhsType, lhsType); 86 } 87 } 88 89 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { 90 94 int pc = codeStream.position; 95 ((Reference) lhs).generateAssignment(currentScope, codeStream, this, valueRequired); 96 codeStream.recordPositionsFrom(pc, this.sourceStart); 99 } 100 101 public static Binding getDirectBinding(Expression someExpression) { 102 if ((someExpression.bits & ASTNode.IgnoreNoEffectAssignCheck) != 0) { 103 return null; 104 } 105 if (someExpression instanceof SingleNameReference) { 106 return ((SingleNameReference)someExpression).binding; 107 } else if (someExpression instanceof FieldReference) { 108 FieldReference fieldRef = (FieldReference)someExpression; 109 if (fieldRef.receiver.isThis() && !(fieldRef.receiver instanceof QualifiedThisReference)) { 110 return fieldRef.binding; 111 } 112 } else if (someExpression instanceof Assignment) { 113 Expression lhs = ((Assignment)someExpression).lhs; 114 if ((lhs.bits & ASTNode.IsStrictlyAssigned) != 0) { 115 return getDirectBinding (((Assignment)someExpression).lhs); 117 } else if (someExpression instanceof PrefixExpression) { 118 return getDirectBinding (((Assignment)someExpression).lhs); 120 } 121 } 122 return null; 126 } 127 128 FieldBinding getLastField(Expression someExpression) { 129 if (someExpression instanceof SingleNameReference) { 130 if ((someExpression.bits & RestrictiveFlagMASK) == Binding.FIELD) { 131 return (FieldBinding) ((SingleNameReference)someExpression).binding; 132 } 133 } else if (someExpression instanceof FieldReference) { 134 return ((FieldReference)someExpression).binding; 135 } else if (someExpression instanceof QualifiedNameReference) { 136 QualifiedNameReference qName = (QualifiedNameReference) someExpression; 137 if (qName.otherBindings == null) { 138 if ((someExpression.bits & RestrictiveFlagMASK) == Binding.FIELD) { 139 return (FieldBinding)qName.binding; 140 } 141 } else { 142 return qName.otherBindings[qName.otherBindings.length - 1]; 143 } 144 } 145 return null; 146 } 147 148 public int nullStatus(FlowInfo flowInfo) { 149 return this.expression.nullStatus(flowInfo); 150 } 151 152 public StringBuffer print(int indent, StringBuffer output) { 153 printIndent(indent, output); 155 return printExpressionNoParenthesis(indent, output); 156 } 157 public StringBuffer printExpression(int indent, StringBuffer output) { 158 output.append('('); 160 return printExpressionNoParenthesis(0, output).append(')'); 161 } 162 163 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { 164 lhs.printExpression(indent, output).append(" = "); return expression.printExpression(0, output); 166 } 167 168 public StringBuffer printStatement(int indent, StringBuffer output) { 169 return print(indent, output).append(';'); 171 } 172 173 public TypeBinding resolveType(BlockScope scope) { 174 this.constant = Constant.NotAConstant; 176 if (!(this.lhs instanceof Reference) || this.lhs.isThis()) { 177 scope.problemReporter().expressionShouldBeAVariable(this.lhs); 178 return null; 179 } 180 TypeBinding lhsType = lhs.resolveType(scope); 181 this.expression.setExpectedType(lhsType); if (lhsType != null) 183 this.resolvedType = lhsType.capture(scope, this.sourceEnd); 184 TypeBinding rhsType = this.expression.resolveType(scope); 185 if (lhsType == null || rhsType == null) { 186 return null; 187 } 188 189 Binding left = getDirectBinding(this.lhs); 191 if (left != null && left == getDirectBinding(this.expression)) { 192 scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName()); 193 } 194 195 if (lhsType != rhsType) scope.compilationUnitScope().recordTypeConversion(lhsType, rhsType); 199 if ((this.expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType) 200 || (lhsType.isBaseType() && BaseTypeBinding.isWidening(lhsType.id, rhsType.id))) 201 || rhsType.isCompatibleWith(lhsType)) { 202 this.expression.computeConversion(scope, lhsType, rhsType); 203 checkAssignment(scope, lhsType, rhsType); 204 if (this.expression instanceof CastExpression 205 && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) { 206 CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression); 207 } 208 return this.resolvedType; 209 } else if (scope.isBoxingCompatibleWith(rhsType, lhsType) 210 || (rhsType.isBaseType() && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 && !lhsType.isBaseType() 213 && this.expression.isConstantValueOfTypeAssignableToType(rhsType, scope.environment().computeBoxingType(lhsType)))) { 214 this.expression.computeConversion(scope, lhsType, rhsType); 215 if (this.expression instanceof CastExpression 216 && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) { 217 CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression); 218 } 219 return this.resolvedType; 220 } 221 scope.problemReporter().typeMismatchError(rhsType, lhsType, this.expression); 222 return lhsType; 223 } 224 225 228 public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { 229 230 TypeBinding type = super.resolveTypeExpecting(scope, expectedType); 231 if (type == null) return null; 232 TypeBinding lhsType = this.resolvedType; 233 TypeBinding rhsType = this.expression.resolvedType; 234 if (expectedType == TypeBinding.BOOLEAN 236 && lhsType == TypeBinding.BOOLEAN 237 && (this.lhs.bits & IsStrictlyAssigned) != 0) { 238 scope.problemReporter().possibleAccidentalBooleanAssignment(this); 239 } 240 checkAssignment(scope, lhsType, rhsType); 241 return type; 242 } 243 244 public void traverse(ASTVisitor visitor, BlockScope scope) { 245 if (visitor.visit(this, scope)) { 246 lhs.traverse(visitor, scope); 247 expression.traverse(visitor, scope); 248 } 249 visitor.endVisit(this, scope); 250 } 251 public LocalVariableBinding localVariableBinding() { 252 return lhs.localVariableBinding(); 253 } 254 } 255 | Popular Tags |