001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.lookup;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.internal.compiler.ast.ASTNode;
014: import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
015: import org.eclipse.jdt.internal.compiler.ast.Annotation;
016: import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
017: import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
018: import org.eclipse.jdt.internal.compiler.impl.Constant;
019: import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
020:
021: public class LocalVariableBinding extends VariableBinding {
022:
023: public int resolvedPosition; // for code generation (position in method context)
024:
025: public static final int UNUSED = 0;
026: public static final int USED = 1;
027: public static final int FAKE_USED = 2;
028: public int useFlag; // for flow analysis (default is UNUSED)
029:
030: public BlockScope declaringScope; // back-pointer to its declaring scope
031: public LocalDeclaration declaration; // for source-positions
032:
033: public int[] initializationPCs;
034: public int initializationCount = 0;
035:
036: // for synthetic local variables
037: // if declaration slot is not positionned, the variable will not be listed in attribute
038: // note that the name of a variable should be chosen so as not to conflict with user ones (usually starting with a space char is all needed)
039: public LocalVariableBinding(char[] name, TypeBinding type,
040: int modifiers, boolean isArgument) {
041: super (name, type, modifiers, isArgument ? Constant.NotAConstant
042: : null);
043: if (isArgument)
044: this .tagBits |= TagBits.IsArgument;
045: }
046:
047: // regular local variable or argument
048: public LocalVariableBinding(LocalDeclaration declaration,
049: TypeBinding type, int modifiers, boolean isArgument) {
050:
051: this (declaration.name, type, modifiers, isArgument);
052: this .declaration = declaration;
053: }
054:
055: /* API
056: * Answer the receiver's binding type from Binding.BindingID.
057: */
058: public final int kind() {
059:
060: return LOCAL;
061: }
062:
063: /*
064: * declaringUniqueKey # scopeIndex(0-based) # varName [# occurrenceCount(0-based)]
065: * p.X { void foo() { int local; int local;} } --> Lp/X;.foo()V#1#local#1
066: */
067: public char[] computeUniqueKey(boolean isLeaf) {
068: StringBuffer buffer = new StringBuffer();
069:
070: // declaring method or type
071: BlockScope scope = this .declaringScope;
072: int occurenceCount = 0;
073: if (scope != null) {
074: // the scope can be null. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=185129
075: MethodScope methodScope = scope instanceof MethodScope ? (MethodScope) scope
076: : scope.enclosingMethodScope();
077: ReferenceContext referenceContext = methodScope.referenceContext;
078: if (referenceContext instanceof AbstractMethodDeclaration) {
079: MethodBinding methodBinding = ((AbstractMethodDeclaration) referenceContext).binding;
080: if (methodBinding != null) {
081: buffer.append(methodBinding
082: .computeUniqueKey(false/*not a leaf*/));
083: }
084: } else if (referenceContext instanceof TypeDeclaration) {
085: TypeBinding typeBinding = ((TypeDeclaration) referenceContext).binding;
086: if (typeBinding != null) {
087: buffer.append(typeBinding
088: .computeUniqueKey(false/*not a leaf*/));
089: }
090: }
091:
092: // scope index
093: getScopeKey(scope, buffer);
094:
095: // find number of occurences of a variable with the same name in the scope
096: LocalVariableBinding[] locals = scope.locals;
097: for (int i = 0; i < scope.localIndex; i++) { // use linear search assuming the number of locals per scope is low
098: LocalVariableBinding local = locals[i];
099: if (CharOperation.equals(this .name, local.name)) {
100: if (this == local)
101: break;
102: occurenceCount++;
103: }
104: }
105: }
106: // variable name
107: buffer.append('#');
108: buffer.append(this .name);
109:
110: // add occurence count to avoid same key for duplicate variables
111: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=149590)
112: if (occurenceCount > 0) {
113: buffer.append('#');
114: buffer.append(occurenceCount);
115: }
116:
117: int length = buffer.length();
118: char[] uniqueKey = new char[length];
119: buffer.getChars(0, length, uniqueKey, 0);
120: return uniqueKey;
121: }
122:
123: public AnnotationBinding[] getAnnotations() {
124: if (this .declaringScope == null) {
125: if ((this .tagBits & TagBits.AnnotationResolved) != 0) {
126: // annotation are already resolved
127: if (this .declaration == null) {
128: return Binding.NO_ANNOTATIONS;
129: }
130: Annotation[] annotations = this .declaration.annotations;
131: if (annotations != null) {
132: int length = annotations.length;
133: AnnotationBinding[] annotationBindings = new AnnotationBinding[length];
134: for (int i = 0; i < length; i++) {
135: AnnotationBinding compilerAnnotation = annotations[i]
136: .getCompilerAnnotation();
137: if (compilerAnnotation == null) {
138: return Binding.NO_ANNOTATIONS;
139: }
140: annotationBindings[i] = compilerAnnotation;
141: }
142: return annotationBindings;
143: }
144: }
145: return Binding.NO_ANNOTATIONS;
146: }
147: SourceTypeBinding sourceType = this .declaringScope
148: .enclosingSourceType();
149: if (sourceType == null)
150: return Binding.NO_ANNOTATIONS;
151:
152: AnnotationBinding[] annotations = sourceType
153: .retrieveAnnotations(this );
154: if ((this .tagBits & TagBits.AnnotationResolved) == 0) {
155: if (((this .tagBits & TagBits.IsArgument) != 0)
156: && this .declaration != null) {
157: Annotation[] annotationNodes = declaration.annotations;
158: if (annotationNodes != null) {
159: int length = annotationNodes.length;
160: ASTNode.resolveAnnotations(this .declaringScope,
161: annotationNodes, this );
162: annotations = new AnnotationBinding[length];
163: for (int i = 0; i < length; i++)
164: annotations[i] = new AnnotationBinding(
165: annotationNodes[i]);
166: setAnnotations(annotations);
167: }
168: }
169: }
170: return annotations;
171: }
172:
173: private void getScopeKey(BlockScope scope, StringBuffer buffer) {
174: int scopeIndex = scope.scopeIndex();
175: if (scopeIndex != -1) {
176: getScopeKey((BlockScope) scope.parent, buffer);
177: buffer.append('#');
178: buffer.append(scopeIndex);
179: }
180: }
181:
182: // Answer whether the variable binding is a secret variable added for code gen purposes
183: public boolean isSecret() {
184:
185: return declaration == null
186: && (this .tagBits & TagBits.IsArgument) == 0;
187: }
188:
189: public void recordInitializationEndPC(int pc) {
190:
191: if (initializationPCs[((initializationCount - 1) << 1) + 1] == -1)
192: initializationPCs[((initializationCount - 1) << 1) + 1] = pc;
193: }
194:
195: public void recordInitializationStartPC(int pc) {
196:
197: if (initializationPCs == null)
198: return;
199: if (initializationCount > 0) {
200: int previousEndPC = initializationPCs[((initializationCount - 1) << 1) + 1];
201: // interval still open, keep using it (108180)
202: if (previousEndPC == -1) {
203: return;
204: }
205: // optimize cases where reopening a contiguous interval
206: if (previousEndPC == pc) {
207: initializationPCs[((initializationCount - 1) << 1) + 1] = -1; // reuse previous interval (its range will be augmented)
208: return;
209: }
210: }
211: int index = initializationCount << 1;
212: if (index == initializationPCs.length) {
213: System
214: .arraycopy(
215: initializationPCs,
216: 0,
217: (initializationPCs = new int[initializationCount << 2]),
218: 0, index);
219: }
220: initializationPCs[index] = pc;
221: initializationPCs[index + 1] = -1;
222: initializationCount++;
223: }
224:
225: public void setAnnotations(AnnotationBinding[] annotations) {
226: if (this .declaringScope == null)
227: return;
228:
229: SourceTypeBinding sourceType = this .declaringScope
230: .enclosingSourceType();
231: if (sourceType != null)
232: sourceType.storeAnnotations(this , annotations);
233: }
234:
235: public String toString() {
236:
237: String s = super .toString();
238: switch (useFlag) {
239: case USED:
240: s += "[pos: " + String.valueOf(resolvedPosition) + "]"; //$NON-NLS-2$ //$NON-NLS-1$
241: break;
242: case UNUSED:
243: s += "[pos: unused]"; //$NON-NLS-1$
244: break;
245: case FAKE_USED:
246: s += "[pos: fake_used]"; //$NON-NLS-1$
247: break;
248: }
249: s += "[id:" + String.valueOf(id) + "]"; //$NON-NLS-2$ //$NON-NLS-1$
250: if (initializationCount > 0) {
251: s += "[pc: "; //$NON-NLS-1$
252: for (int i = 0; i < initializationCount; i++) {
253: if (i > 0)
254: s += ", "; //$NON-NLS-1$
255: s += String.valueOf(initializationPCs[i << 1])
256: + "-" + ((initializationPCs[(i << 1) + 1] == -1) ? "?" : String.valueOf(initializationPCs[(i << 1) + 1])); //$NON-NLS-2$ //$NON-NLS-1$
257: }
258: s += "]"; //$NON-NLS-1$
259: }
260: return s;
261: }
262: }
|