added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / LocalVariableBinding.java
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.lookup;
12
13 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
14 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
15 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
16 import org.eclipse.jdt.internal.compiler.impl.Constant;
17 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
18
19 public class LocalVariableBinding extends VariableBinding {
20
21         public boolean isArgument;
22         public int resolvedPosition; // for code generation (position in method context)
23         
24         public static final int UNUSED = 0;
25         public static final int USED = 1;
26         public static final int FAKE_USED = 2;
27         public int useFlag; // for flow analysis (default is UNUSED)
28         
29         public BlockScope declaringScope; // back-pointer to its declaring scope
30         public LocalDeclaration declaration; // for source-positions
31
32         public int[] initializationPCs;
33         public int initializationCount = 0;
34
35         // for synthetic local variables        
36         // if declaration slot is not positionned, the variable will not be listed in attribute
37         // 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)
38         public LocalVariableBinding(char[] name, TypeBinding type, int modifiers, boolean isArgument) {
39                 super(name, type, modifiers, isArgument ? Constant.NotAConstant : null);
40                 this.isArgument = isArgument;
41         }
42         
43         // regular local variable or argument
44         public LocalVariableBinding(LocalDeclaration declaration, TypeBinding type, int modifiers, boolean isArgument) {
45
46                 this(declaration.name, type, modifiers, isArgument);
47                 this.declaration = declaration;
48         }
49
50         /* API
51         * Answer the receiver's binding type from Binding.BindingID.
52         */
53         public final int kind() {
54
55                 return LOCAL;
56         }
57         
58         /*
59          * declaringUniqueKey # scopeIndex / varName
60          * p.X { void foo() { int local; } } --> Lp/X;.foo()V#1/local
61          */
62         public char[] computeUniqueKey() {
63                 StringBuffer buffer = new StringBuffer();
64                 
65                 // declaring method or type
66                 BlockScope scope = this.declaringScope;
67                 MethodScope methodScope = scope instanceof MethodScope ? (MethodScope) scope : scope.enclosingMethodScope();
68                 ReferenceContext referenceContext = methodScope.referenceContext;
69                 if (referenceContext instanceof AbstractMethodDeclaration) {
70                         MethodBinding methodBinding = ((AbstractMethodDeclaration) referenceContext).binding;
71                         if (methodBinding != null) {
72                                 buffer.append(methodBinding.computeUniqueKey());
73                         }
74                 } else if (referenceContext instanceof TypeDeclaration) {
75                         TypeBinding typeBinding = ((TypeDeclaration) referenceContext).binding;
76                         if (typeBinding != null) {
77                                 buffer.append(typeBinding.computeUniqueKey());
78                         }
79                 }
80
81                 // scope index
82                 getScopeKey(scope, buffer);
83
84                 // variable name
85                 buffer.append('#');
86                 buffer.append(this.name);
87                 
88                 int length = buffer.length();
89                 char[] uniqueKey = new char[length];
90                 buffer.getChars(0, length, uniqueKey, 0);
91                 return uniqueKey;
92         }
93         
94         private void getScopeKey(BlockScope scope, StringBuffer buffer) {
95                 int scopeIndex = scope.scopeIndex();
96                 if (scopeIndex != -1) {
97                         getScopeKey((BlockScope)scope.parent, buffer);
98                         buffer.append('#');
99                         buffer.append(scopeIndex);
100                 }
101         }
102         
103         // Answer whether the variable binding is a secret variable added for code gen purposes
104         public boolean isSecret() {
105
106                 return declaration == null && !isArgument;
107         }
108
109         public void recordInitializationEndPC(int pc) {
110
111                 if (initializationPCs[((initializationCount - 1) << 1) + 1] == -1)
112                         initializationPCs[((initializationCount - 1) << 1) + 1] = pc;
113         }
114
115         public void recordInitializationStartPC(int pc) {
116
117                 if (initializationPCs == null)  return;
118                 // optimize cases where reopening a contiguous interval
119                 if ((initializationCount > 0) && (initializationPCs[ ((initializationCount - 1) << 1) + 1] == pc)) {
120                         initializationPCs[ ((initializationCount - 1) << 1) + 1] = -1; // reuse previous interval (its range will be augmented)
121                 } else {
122                         int index = initializationCount << 1;
123                         if (index == initializationPCs.length) {
124                                 System.arraycopy(initializationPCs, 0, (initializationPCs = new int[initializationCount << 2]), 0, index);
125                         }
126                         initializationPCs[index] = pc;
127                         initializationPCs[index + 1] = -1;
128                         initializationCount++;
129                 }
130         }
131
132         public String toString() {
133
134                 String s = super.toString();
135                 switch (useFlag){
136                         case USED:
137                                 s += "[pos: " + String.valueOf(resolvedPosition) + "]"; //$NON-NLS-2$ //$NON-NLS-1$
138                                 break;
139                         case UNUSED:
140                                 s += "[pos: unused]"; //$NON-NLS-1$
141                                 break;
142                         case FAKE_USED:
143                                 s += "[pos: fake_used]"; //$NON-NLS-1$
144                                 break;
145                 }
146                 s += "[id:" + String.valueOf(id) + "]"; //$NON-NLS-2$ //$NON-NLS-1$
147                 if (initializationCount > 0) {
148                         s += "[pc: "; //$NON-NLS-1$
149                         for (int i = 0; i < initializationCount; i++) {
150                                 if (i > 0)
151                                         s += ", "; //$NON-NLS-1$
152                                 s += String.valueOf(initializationPCs[i << 1]) + "-" + ((initializationPCs[(i << 1) + 1] == -1) ? "?" : String.valueOf(initializationPCs[(i<< 1) + 1])); //$NON-NLS-2$ //$NON-NLS-1$
153                         }
154                         s += "]"; //$NON-NLS-1$
155                 }
156                 return s;
157         }
158 }