1 /******************************************************************************* 2 * Copyright (c) 2000, 2004 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Common Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/cpl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.ASTVisitor; 14 import org.eclipse.jdt.internal.compiler.impl.*; 15 import org.eclipse.jdt.internal.compiler.codegen.*; 16 import org.eclipse.jdt.internal.compiler.flow.*; 17 import org.eclipse.jdt.internal.compiler.lookup.*; 18 19 public class LocalDeclaration extends AbstractVariableDeclaration { 20 21 public LocalVariableBinding binding; 22 LocalDeclaration( char[] name, int sourceStart, int sourceEnd)23 public LocalDeclaration( 24 char[] name, 25 int sourceStart, 26 int sourceEnd) { 27 28 this.name = name; 29 this.sourceStart = sourceStart; 30 this.sourceEnd = sourceEnd; 31 this.declarationEnd = sourceEnd; 32 } 33 analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)34 public FlowInfo analyseCode( 35 BlockScope currentScope, 36 FlowContext flowContext, 37 FlowInfo flowInfo) { 38 39 // record variable initialization if any 40 if (flowInfo.isReachable()) { 41 bits |= IsLocalDeclarationReachableMASK; // only set if actually reached 42 } 43 if (initialization == null) 44 return flowInfo; 45 46 flowInfo = 47 initialization 48 .analyseCode(currentScope, flowContext, flowInfo) 49 .unconditionalInits(); 50 51 // final int i = (i = 0); 52 // no need to complain since (i = 0) part will get the blame 53 //if (binding.isFinal() && flowInfo.isPotentiallyAssigned(binding)) { 54 // currentScope.problemReporter().duplicateInitializationOfFinalLocal(binding, this); 55 //} 56 57 flowInfo.markAsDefinitelyAssigned(binding); 58 return flowInfo; 59 } 60 checkModifiers()61 public void checkModifiers() { 62 63 //only potential valid modifier is <<final>> 64 if (((modifiers & AccJustFlag) & ~AccFinal) != 0) 65 //AccModifierProblem -> other (non-visibility problem) 66 //AccAlternateModifierProblem -> duplicate modifier 67 //AccModifierProblem | AccAlternateModifierProblem -> visibility problem" 68 69 modifiers = (modifiers & ~AccAlternateModifierProblem) | AccModifierProblem; 70 } 71 72 /** 73 * Code generation for a local declaration: 74 * i.e. normal assignment to a local variable + unused variable handling 75 */ generateCode(BlockScope currentScope, CodeStream codeStream)76 public void generateCode(BlockScope currentScope, CodeStream codeStream) { 77 78 // even if not reachable, variable must be added to visible if allocated (28298) 79 if (binding.resolvedPosition != -1) { 80 codeStream.addVisibleLocalVariable(binding); 81 } 82 if ((bits & IsReachableMASK) == 0) { 83 return; 84 } 85 int pc = codeStream.position; 86 Constant inlinedValue; 87 88 // something to initialize? 89 if (initialization != null) { 90 // initialize to constant value? 91 if ((inlinedValue = initialization.constant) != NotAConstant) { 92 // forget initializing unused or final locals set to constant value (final ones are inlined) 93 if (binding.resolvedPosition != -1) { // may need to preserve variable 94 int initPC = codeStream.position; 95 codeStream.generateConstant(inlinedValue, initialization.implicitConversion); 96 codeStream.recordPositionsFrom(initPC, initialization.sourceStart); 97 codeStream.store(binding, false); 98 binding.recordInitializationStartPC(codeStream.position); 99 // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index 100 // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index 101 } 102 } else { // initializing to non-constant value 103 initialization.generateCode(currentScope, codeStream, true); 104 // if binding unused generate then discard the value 105 if (binding.resolvedPosition != -1) { 106 // 26903, need extra cast to store null in array local var 107 if (binding.type.isArrayType() 108 && (initialization.resolvedType == NullBinding // arrayLoc = null 109 || ((initialization instanceof CastExpression) // arrayLoc = (type[])null 110 && (((CastExpression)initialization).innermostCastedExpression().resolvedType == NullBinding)))){ 111 codeStream.checkcast(binding.type); 112 } 113 codeStream.store(binding, false); 114 if (binding.initializationCount == 0) { 115 /* Variable may have been initialized during the code initializing it 116 e.g. int i = (i = 1); 117 */ 118 binding.recordInitializationStartPC(codeStream.position); 119 // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index 120 // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index 121 } 122 } else { 123 if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) { 124 codeStream.pop2(); 125 } else { 126 codeStream.pop(); 127 } 128 } 129 } 130 } 131 codeStream.recordPositionsFrom(pc, this.sourceStart); 132 } 133 resolve(BlockScope scope)134 public void resolve(BlockScope scope) { 135 136 // create a binding and add it to the scope 137 TypeBinding variableType = type.resolveType(scope); 138 139 checkModifiers(); 140 141 if (variableType != null) { 142 if (variableType == VoidBinding) { 143 scope.problemReporter().variableTypeCannotBeVoid(this); 144 return; 145 } 146 if (variableType.isArrayType() && ((ArrayBinding) variableType).leafComponentType == VoidBinding) { 147 scope.problemReporter().variableTypeCannotBeVoidArray(this); 148 return; 149 } 150 } 151 152 Binding existingVariable = scope.getBinding(name, BindingIds.VARIABLE, this, false /*do not resolve hidden field*/); 153 boolean shouldInsertInScope = true; 154 if (existingVariable != null && existingVariable.isValidBinding()){ 155 if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) { 156 shouldInsertInScope = false; 157 scope.problemReporter().redefineLocal(this); 158 } else { 159 scope.problemReporter().localVariableHiding(this, existingVariable, false); 160 } 161 } 162 163 if (shouldInsertInScope) { 164 if ((modifiers & AccFinal)!= 0 && this.initialization == null) { 165 modifiers |= AccBlankFinal; 166 } 167 binding = new LocalVariableBinding(this, variableType, modifiers, false); 168 scope.addLocalVariable(binding); 169 binding.setConstant(NotAConstant); 170 // allow to recursivelly target the binding.... 171 // the correct constant is harmed if correctly computed at the end of this method 172 } 173 174 if (variableType == null) { 175 if (initialization != null) 176 initialization.resolveType(scope); // want to report all possible errors 177 return; 178 } 179 180 // store the constant for final locals 181 if (initialization != null) { 182 if (initialization instanceof ArrayInitializer) { 183 TypeBinding initializationType = initialization.resolveTypeExpecting(scope, variableType); 184 if (initializationType != null) { 185 ((ArrayInitializer) initialization).binding = (ArrayBinding) initializationType; 186 initialization.computeConversion(scope, variableType, initializationType); 187 } 188 } else { 189 this.initialization.setExpectedType(variableType); 190 TypeBinding initializationType = this.initialization.resolveType(scope); 191 if (initializationType != null) { 192 if (initialization.isConstantValueOfTypeAssignableToType(initializationType, variableType) 193 || (variableType.isBaseType() && BaseTypeBinding.isWidening(variableType.id, initializationType.id)) 194 || initializationType.isCompatibleWith(variableType)) { 195 this.initialization.computeConversion(scope, variableType, initializationType); 196 if (initializationType.isRawType() && (variableType.isBoundParameterizedType() || variableType.isGenericType())) { 197 scope.problemReporter().unsafeRawConversion(this.initialization, initializationType, variableType); 198 } 199 } else { 200 scope.problemReporter().typeMismatchError(initializationType, variableType, this); 201 } 202 } 203 } 204 205 // change the constant in the binding when it is final 206 // (the optimization of the constant propagation will be done later on) 207 // cast from constant actual type to variable type 208 if (binding != null) { 209 binding.setConstant( 210 binding.isFinal() 211 ? initialization.constant.castTo((variableType.id << 4) + initialization.constant.typeID()) 212 : NotAConstant); 213 } 214 } 215 } 216 traverse(ASTVisitor visitor, BlockScope scope)217 public void traverse(ASTVisitor visitor, BlockScope scope) { 218 219 if (visitor.visit(this, scope)) { 220 type.traverse(visitor, scope); 221 if (initialization != null) 222 initialization.traverse(visitor, scope); 223 } 224 visitor.endVisit(this, scope); 225 } 226 } 227