KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > jjs > impl > GenerateJavaAST


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.jjs.impl;
17
18 import com.google.gwt.dev.jjs.InternalCompilerException;
19 import com.google.gwt.dev.jjs.SourceInfo;
20 import com.google.gwt.dev.jjs.ast.CanBeStatic;
21 import com.google.gwt.dev.jjs.ast.HasEnclosingType;
22 import com.google.gwt.dev.jjs.ast.HasName;
23 import com.google.gwt.dev.jjs.ast.JArrayRef;
24 import com.google.gwt.dev.jjs.ast.JArrayType;
25 import com.google.gwt.dev.jjs.ast.JAssertStatement;
26 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
27 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
28 import com.google.gwt.dev.jjs.ast.JBlock;
29 import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
30 import com.google.gwt.dev.jjs.ast.JBreakStatement;
31 import com.google.gwt.dev.jjs.ast.JCaseStatement;
32 import com.google.gwt.dev.jjs.ast.JCastOperation;
33 import com.google.gwt.dev.jjs.ast.JCharLiteral;
34 import com.google.gwt.dev.jjs.ast.JClassType;
35 import com.google.gwt.dev.jjs.ast.JConditional;
36 import com.google.gwt.dev.jjs.ast.JContinueStatement;
37 import com.google.gwt.dev.jjs.ast.JDoStatement;
38 import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
39 import com.google.gwt.dev.jjs.ast.JExpression;
40 import com.google.gwt.dev.jjs.ast.JField;
41 import com.google.gwt.dev.jjs.ast.JFieldRef;
42 import com.google.gwt.dev.jjs.ast.JFloatLiteral;
43 import com.google.gwt.dev.jjs.ast.JForStatement;
44 import com.google.gwt.dev.jjs.ast.JIfStatement;
45 import com.google.gwt.dev.jjs.ast.JInstanceOf;
46 import com.google.gwt.dev.jjs.ast.JIntLiteral;
47 import com.google.gwt.dev.jjs.ast.JLabel;
48 import com.google.gwt.dev.jjs.ast.JLabeledStatement;
49 import com.google.gwt.dev.jjs.ast.JLiteral;
50 import com.google.gwt.dev.jjs.ast.JLocal;
51 import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
52 import com.google.gwt.dev.jjs.ast.JLocalRef;
53 import com.google.gwt.dev.jjs.ast.JLongLiteral;
54 import com.google.gwt.dev.jjs.ast.JMethod;
55 import com.google.gwt.dev.jjs.ast.JMethodCall;
56 import com.google.gwt.dev.jjs.ast.JNewArray;
57 import com.google.gwt.dev.jjs.ast.JNewInstance;
58 import com.google.gwt.dev.jjs.ast.JNode;
59 import com.google.gwt.dev.jjs.ast.JParameter;
60 import com.google.gwt.dev.jjs.ast.JParameterRef;
61 import com.google.gwt.dev.jjs.ast.JPostfixOperation;
62 import com.google.gwt.dev.jjs.ast.JPrefixOperation;
63 import com.google.gwt.dev.jjs.ast.JProgram;
64 import com.google.gwt.dev.jjs.ast.JReferenceType;
65 import com.google.gwt.dev.jjs.ast.JReturnStatement;
66 import com.google.gwt.dev.jjs.ast.JStatement;
67 import com.google.gwt.dev.jjs.ast.JStringLiteral;
68 import com.google.gwt.dev.jjs.ast.JSwitchStatement;
69 import com.google.gwt.dev.jjs.ast.JThrowStatement;
70 import com.google.gwt.dev.jjs.ast.JTryStatement;
71 import com.google.gwt.dev.jjs.ast.JType;
72 import com.google.gwt.dev.jjs.ast.JUnaryOperator;
73 import com.google.gwt.dev.jjs.ast.JVariable;
74 import com.google.gwt.dev.jjs.ast.JVariableRef;
75 import com.google.gwt.dev.jjs.ast.JWhileStatement;
76 import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
77 import com.google.gwt.dev.jjs.ast.js.JsniMethod;
78 import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
79 import com.google.gwt.dev.js.ast.JsContext;
80 import com.google.gwt.dev.js.ast.JsFunction;
81 import com.google.gwt.dev.js.ast.JsNameRef;
82 import com.google.gwt.dev.js.ast.JsSourceInfo;
83 import com.google.gwt.dev.js.ast.JsVisitor;
84
85 import org.eclipse.jdt.core.compiler.IProblem;
86 import org.eclipse.jdt.internal.compiler.CompilationResult;
87 import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
88 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
89 import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
90 import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
91 import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
92 import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
93 import org.eclipse.jdt.internal.compiler.ast.AssertStatement;
94 import org.eclipse.jdt.internal.compiler.ast.Assignment;
95 import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
96 import org.eclipse.jdt.internal.compiler.ast.Block;
97 import org.eclipse.jdt.internal.compiler.ast.BreakStatement;
98 import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
99 import org.eclipse.jdt.internal.compiler.ast.CastExpression;
100 import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
101 import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
102 import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
103 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
104 import org.eclipse.jdt.internal.compiler.ast.ContinueStatement;
105 import org.eclipse.jdt.internal.compiler.ast.DoStatement;
106 import org.eclipse.jdt.internal.compiler.ast.EmptyStatement;
107 import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
108 import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
109 import org.eclipse.jdt.internal.compiler.ast.Expression;
110 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
111 import org.eclipse.jdt.internal.compiler.ast.FieldReference;
112 import org.eclipse.jdt.internal.compiler.ast.ForStatement;
113 import org.eclipse.jdt.internal.compiler.ast.IfStatement;
114 import org.eclipse.jdt.internal.compiler.ast.Initializer;
115 import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
116 import org.eclipse.jdt.internal.compiler.ast.LabeledStatement;
117 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
118 import org.eclipse.jdt.internal.compiler.ast.MessageSend;
119 import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
120 import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression;
121 import org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
122 import org.eclipse.jdt.internal.compiler.ast.PrefixExpression;
123 import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
124 import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
125 import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
126 import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
127 import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
128 import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
129 import org.eclipse.jdt.internal.compiler.ast.Statement;
130 import org.eclipse.jdt.internal.compiler.ast.SuperReference;
131 import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
132 import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement;
133 import org.eclipse.jdt.internal.compiler.ast.ThisReference;
134 import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
135 import org.eclipse.jdt.internal.compiler.ast.TryStatement;
136 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
137 import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
138 import org.eclipse.jdt.internal.compiler.ast.WhileStatement;
139 import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
140 import org.eclipse.jdt.internal.compiler.impl.ByteConstant;
141 import org.eclipse.jdt.internal.compiler.impl.CharConstant;
142 import org.eclipse.jdt.internal.compiler.impl.Constant;
143 import org.eclipse.jdt.internal.compiler.impl.DoubleConstant;
144 import org.eclipse.jdt.internal.compiler.impl.FloatConstant;
145 import org.eclipse.jdt.internal.compiler.impl.IntConstant;
146 import org.eclipse.jdt.internal.compiler.impl.LongConstant;
147 import org.eclipse.jdt.internal.compiler.impl.ShortConstant;
148 import org.eclipse.jdt.internal.compiler.impl.StringConstant;
149 import org.eclipse.jdt.internal.compiler.lookup.Binding;
150 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
151 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
152 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
153 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
154 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
155 import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding;
156 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
157 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
158 import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
159 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
160 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
161 import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
162 import org.eclipse.jdt.internal.compiler.problem.ProblemHandler;
163 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
164
165 import java.lang.reflect.InvocationTargetException JavaDoc;
166 import java.lang.reflect.Method JavaDoc;
167 import java.util.ArrayList JavaDoc;
168 import java.util.Collections JavaDoc;
169 import java.util.HashMap JavaDoc;
170 import java.util.IdentityHashMap JavaDoc;
171 import java.util.Iterator JavaDoc;
172 import java.util.LinkedList JavaDoc;
173 import java.util.List JavaDoc;
174 import java.util.Map JavaDoc;
175
176 /**
177  * This is the big kahuna where most of the nitty gritty of creating our AST
178  * happens. BuildTypeMap must have already run so we have valid mappings between
179  * JDT nodes and our already-created AST nodes.
180  */

181 public class GenerateJavaAST {
182
183   /**
184    * Visit the JDT AST and produce our own AST into the passed-in TypeMap's
185    * JProgram. By the end of this pass, the produced AST should contain every
186    * piece of information we'll ever need about the code. The JDT nodes should
187    * never again be referenced after this.
188    *
189    * This is implemented as a reflective visitor for JDT's AST. The advantage of
190    * doing it reflectively is that if we run into any JDT nodes we can't handle,
191    * we'll automatically throw an exception. If we had subclassed
192    * {@link org.eclipse.jdt.internal.compiler.ast.ASTNode} we'd have to override
193    * every single method and explicitly throw an exception to get the same
194    * behavior.
195    *
196    * NOTE ON JDT FORCED OPTIMIZATIONS - If JDT statically determines that a
197    * section of code in unreachable, it won't fully resolve that section of
198    * code. This invalid-state code causes us major problems. As a result, we
199    * have to optimize out those dead blocks early and never try to translate
200    * them to our AST.
201    */

202   private static class JavaASTGenerationVisitor {
203
204     private static String JavaDoc getJsniSig(JMethod method) {
205       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
206       sb.append(method.getName());
207       sb.append("(");
208       for (int i = 0; i < method.getOriginalParamTypes().size(); ++i) {
209         JType type = (JType) method.getOriginalParamTypes().get(i);
210         sb.append(type.getJsniSignatureName());
211       }
212       sb.append(")");
213       return sb.toString();
214     }
215
216     private static InternalCompilerException translateException(JNode node,
217         Throwable JavaDoc e) {
218       InternalCompilerException ice;
219       if (e instanceof InternalCompilerException) {
220         ice = (InternalCompilerException) e;
221         ice.addNode(node);
222       } else {
223         ice = new InternalCompilerException(node,
224             "Error constructing Java AST", e);
225       }
226       return ice;
227     }
228
229     private Object JavaDoc[] args = new Object JavaDoc[1];
230
231     private JReferenceType currentClass;
232
233     private ClassScope currentClassScope;
234
235     private String JavaDoc currentFileName;
236
237     private JMethod currentMethod;
238
239     private MethodScope currentMethodScope;
240
241     private int[] currentSeparatorPositions;
242
243     private final Map JavaDoc/* <JMethod, Map<String, JLabel>> */labelMap = new IdentityHashMap JavaDoc();
244
245     private Class JavaDoc[] params = new Class JavaDoc[1];
246
247     private final JProgram program;
248
249     private final TypeMap typeMap;
250
251     public JavaASTGenerationVisitor(TypeMap typeMap) {
252       this.typeMap = typeMap;
253       program = this.typeMap.getProgram();
254     }
255
256     /**
257      * We emulate static initializers and intance initializers as methods. As in
258      * other cases, this gives us: simpler AST, easier to optimize, more like
259      * output JavaScript.
260      */

261     public void processType(TypeDeclaration x) {
262       currentClass = (JReferenceType) typeMap.get(x.binding);
263       try {
264         currentClassScope = x.scope;
265         currentSeparatorPositions = x.compilationResult.lineSeparatorPositions;
266         currentFileName = String.valueOf(x.compilationResult.fileName);
267
268         if (x.fields != null) {
269           // Process fields
270
for (int i = 0, n = x.fields.length; i < n; ++i) {
271             FieldDeclaration fieldDeclaration = x.fields[i];
272             if (fieldDeclaration.isStatic()) {
273               // clinit
274
currentMethod = (JMethod) currentClass.methods.get(0);
275               currentMethodScope = x.staticInitializerScope;
276             } else {
277               // init
278
currentMethod = (JMethod) currentClass.methods.get(1);
279               currentMethodScope = x.initializerScope;
280             }
281
282             if (fieldDeclaration instanceof Initializer) {
283               assert (currentClass instanceof JClassType);
284               processInitializer((Initializer) fieldDeclaration);
285             } else {
286               processField(fieldDeclaration);
287             }
288           }
289         }
290
291         currentMethodScope = null;
292         currentMethod = null;
293
294         if (x.methods != null) {
295           // Process methods
296
for (int i = 0, n = x.methods.length; i < n; ++i) {
297             if (x.methods[i].isConstructor()) {
298               assert (currentClass instanceof JClassType);
299               processConstructor((ConstructorDeclaration) x.methods[i]);
300             } else if (x.methods[i].isClinit()) {
301               // nothing to do
302
} else {
303               processMethod(x.methods[i]);
304             }
305           }
306         }
307
308         currentClassScope = null;
309         currentClass = null;
310         currentSeparatorPositions = null;
311         currentFileName = null;
312       } catch (Throwable JavaDoc e) {
313         throw translateException(currentClass, e);
314       }
315     }
316
317     /**
318      * This is the guts of the "reflective" part of this visitor. Try to find a
319      * "process" method that exactly matches the run-time type of the argument.
320      */

321     protected JNode dispatch(String JavaDoc name, Object JavaDoc child) {
322       if (child == null) {
323         return null;
324       }
325
326       try {
327         params[0] = child.getClass();
328         Method method = getClass().getDeclaredMethod(name, params);
329         args[0] = child;
330         return (JNode) method.invoke(this, args);
331       } catch (Throwable JavaDoc e) {
332         if (e instanceof InvocationTargetException JavaDoc) {
333           e = ((InvocationTargetException JavaDoc) e).getTargetException();
334         }
335         throw translateException(child, e);
336       }
337     }
338
339     /**
340      * Process an Expression type node reflectively; must return a JExpression.
341      */

342     protected JExpression dispProcessExpression(Expression x) {
343       /*
344        * Note that we always prefer a JDT-computed constant value to the actual
345        * written expression. (Let's hope JDT is always right.) This means we
346        * don't have to write processExpression methods for the numerous JDT
347        * literal nodes because they ALWAYS have a constant value.
348        */

349       if (x != null && x.constant != null
350           && x.constant != Constant.NotAConstant) {
351         return (JExpression) dispatch("processConstant", x.constant);
352       }
353       return (JExpression) dispatch("processExpression", x);
354     }
355
356     /**
357      * Process an Statement type node reflectively; must return a JStatement.
358      */

359     protected JStatement dispProcessStatement(Statement x) {
360       JStatement stmt;
361       if (x instanceof Expression) {
362         JExpression expr = dispProcessExpression((Expression) x);
363         if (expr == null) {
364           return null;
365         }
366         stmt = expr.makeStatement();
367       } else {
368         stmt = (JStatement) dispatch("processStatement", x);
369       }
370       return stmt;
371     }
372
373     JBooleanLiteral processConstant(BooleanConstant x) {
374       return program.getLiteralBoolean(x.booleanValue());
375     }
376
377     JIntLiteral processConstant(ByteConstant x) {
378       return program.getLiteralInt(x.byteValue());
379     }
380
381     JCharLiteral processConstant(CharConstant x) {
382       return program.getLiteralChar(x.charValue());
383     }
384
385     JDoubleLiteral processConstant(DoubleConstant x) {
386       return program.getLiteralDouble(x.doubleValue());
387     }
388
389     JFloatLiteral processConstant(FloatConstant x) {
390       return program.getLiteralFloat(x.floatValue());
391     }
392
393     JIntLiteral processConstant(IntConstant x) {
394       return program.getLiteralInt(x.intValue());
395     }
396
397     JLongLiteral processConstant(LongConstant x) {
398       return program.getLiteralLong(x.longValue());
399     }
400
401     JIntLiteral processConstant(ShortConstant x) {
402       return program.getLiteralInt(x.shortValue());
403     }
404
405     JStringLiteral processConstant(StringConstant x) {
406       return program.getLiteralString(x.stringValue().toCharArray());
407     }
408
409     /**
410      * Weird: we used to have JConstructor (and JConstructorCall) in our AST,
411      * but we got rid of them completely and instead model them as instance
412      * methods whose qualifier is a naked no-argument new operation.
413      *
414      * There are several reasons we do it this way:
415      *
416      * 1) When spitting our AST back to Java code (for verification purposes),
417      * we found it was impossible to correctly emulate nested classes as
418      * non-nested classes using traditional constructor syntax. It boiled down
419      * to the fact that you really HAVE to assign your synthetic arguments to
420      * your synthetic fields BEFORE calling your superclass constructor (because
421      * it might call you back polymorphically). And trying to do that in
422      * straight Java is a semantic error, a super call must be the first
423      * statement of your constructor.
424      *
425      * 2) It's a lot more like how we'll be generating JavaScript eventually.
426      *
427      * 3) It's a lot easier to optimize; the same optimizations work on our
428      * synthetic fields as work on any user fields. In fact, once we're past AST
429      * generation, we throw away all information about what's synthetic.
430      *
431      * The order of emulation is: - assign all synthetic fields from synthetic
432      * args - call our super constructor emulation method - call our instance
433      * initializer emulation method - run user code - return this
434      */

435     void processConstructor(ConstructorDeclaration x) {
436       JMethod ctor = (JMethod) typeMap.get(x.binding);
437       try {
438         SourceInfo info = ctor.body.getSourceInfo();
439
440         currentMethod = ctor;
441         currentMethodScope = x.scope;
442
443         JMethodCall superOrThisCall = null;
444         ExplicitConstructorCall ctorCall = x.constructorCall;
445         if (ctorCall != null) {
446           superOrThisCall = (JMethodCall) dispatch("processExpression",
447               ctorCall);
448         }
449
450         /*
451          * Determine if we have an explicit this call. The presence of an
452          * explicit this call indicates we can skip certain initialization steps
453          * (as the callee will perform those steps for us). These skippable
454          * steps are 1) assigning synthetic args to fields and 2) running
455          * initializers.
456          */

457         boolean hasExplicitThis = (ctorCall != null)
458             && !ctorCall.isSuperAccess();
459
460         JClassType enclosingType = (JClassType) ctor.getEnclosingType();
461
462         // Call clinit; $clinit is always in position 0.
463
JMethod clinitMethod = (JMethod) enclosingType.methods.get(0);
464         JMethodCall clinitCall = new JMethodCall(program, info, null,
465             clinitMethod);
466         ctor.body.statements.add(clinitCall.makeStatement());
467
468         /*
469          * All synthetic fields must be assigned, unless we have an explicit
470          * this constructor call, in which case the callee will assign them for
471          * us.
472          */

473         if (!hasExplicitThis) {
474           ReferenceBinding declaringClass = x.binding.declaringClass;
475           if (declaringClass instanceof NestedTypeBinding) {
476             Iterator JavaDoc/* <JParameter> */paramIt = getSyntheticsIterator(ctor);
477             NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
478             if (nestedBinding.enclosingInstances != null) {
479               for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
480                 SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
481                 JParameter param = (JParameter) paramIt.next();
482                 if (arg.matchingField != null) {
483                   JField field = (JField) typeMap.get(arg);
484                   ctor.body.statements.add(program.createAssignmentStmt(info,
485                       createVariableRef(info, field), createVariableRef(info,
486                           param)));
487                 }
488               }
489             }
490
491             if (nestedBinding.outerLocalVariables != null) {
492               for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
493                 SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
494                 JParameter param = (JParameter) paramIt.next();
495                 JField field = (JField) typeMap.get(arg);
496                 ctor.body.statements.add(program.createAssignmentStmt(info,
497                     createVariableRef(info, field), createVariableRef(info,
498                         param)));
499               }
500             }
501           }
502         }
503
504         // optional this or super constructor call
505
if (superOrThisCall != null) {
506           ctor.body.statements.add(superOrThisCall.makeStatement());
507         }
508
509         JExpression thisRef = createThisRef(info, enclosingType);
510
511         /*
512          * Call the synthetic instance initializer method, unless we have an
513          * explicit this constructor call, in which case the callee will.
514          */

515         if (!hasExplicitThis) {
516           // $init is always in position 1 (clinit is in 0)
517
JMethod initMethod = (JMethod) enclosingType.methods.get(1);
518           JMethodCall initCall = new JMethodCall(program, info, thisRef,
519               initMethod);
520           ctor.body.statements.add(initCall.makeStatement());
521         }
522
523         // user code (finally!)
524
if (x.statements != null) {
525           for (int i = 0, n = x.statements.length; i < n; ++i) {
526             Statement origStmt = x.statements[i];
527             JStatement jstmt = dispProcessStatement(origStmt);
528             if (jstmt != null) {
529               ctor.body.statements.add(jstmt);
530             }
531           }
532         }
533
534         currentMethodScope = null;
535         currentMethod = null;
536
537         // synthesize a return statement to emulate returning the new object
538
ctor.body.statements.add(new JReturnStatement(program, null, thisRef));
539       } catch (Throwable JavaDoc e) {
540         throw translateException(ctor, e);
541       }
542     }
543
544     JExpression processExpression(AllocationExpression x) {
545       SourceInfo info = makeSourceInfo(x);
546       SourceTypeBinding typeBinding = (SourceTypeBinding) x.resolvedType;
547       if (typeBinding.constantPoolName() == null) {
548         /*
549          * Weird case: if JDT determines that this local class is totally
550          * uninstantiable, it won't bother allocating a local name.
551          */

552         return program.getLiteralNull();
553       }
554       JClassType newType = (JClassType) typeMap.get(typeBinding);
555       MethodBinding b = x.binding;
556       JMethod ctor = (JMethod) typeMap.get(b);
557       JMethodCall call;
558       JClassType javaLangString = program.getTypeJavaLangString();
559       if (newType == javaLangString) {
560         /*
561          * MAGIC: java.lang.String is implemented as a JavaScript String
562          * primitive with a modified prototype. This requires funky handling of
563          * constructor calls. We find a method named _String() whose signature
564          * matches the requested constructor
565          */

566         int ctorArgc = ctor.params.size();
567         JMethod targetMethod = null;
568         outer : for (int j = 0; j < javaLangString.methods.size(); ++j) {
569           JMethod method = (JMethod) javaLangString.methods.get(j);
570           if (method.getName().equals("_String")
571               && method.params.size() == ctorArgc) {
572             for (int i = 0; i < ctorArgc; ++i) {
573               JParameter mparam = (JParameter) method.params.get(i);
574               JParameter cparam = (JParameter) ctor.params.get(i);
575               if (mparam.getType() != cparam.getType()) {
576                 continue outer;
577               }
578             }
579             targetMethod = method;
580             break;
581           }
582         }
583         if (targetMethod == null) {
584           throw new InternalCompilerException(
585               "String constructor error; no matching implementation.");
586         }
587         call = new JMethodCall(program, makeSourceInfo(x), null, targetMethod);
588       } else {
589         JNewInstance newInstance = new JNewInstance(program, info, newType);
590         call = new JMethodCall(program, info, newInstance, ctor);
591       }
592
593       // Plain old regular user arguments
594
if (x.arguments != null) {
595         for (int i = 0, n = x.arguments.length; i < n; ++i) {
596           call.getArgs().add(dispProcessExpression(x.arguments[i]));
597         }
598       }
599
600       // Synthetic args for inner classes
601
ReferenceBinding targetBinding = b.declaringClass;
602       if (targetBinding.isNestedType() && !targetBinding.isStatic()) {
603         NestedTypeBinding nestedBinding = (NestedTypeBinding) targetBinding;
604         // Synthetic this args for inner classes
605
if (nestedBinding.enclosingInstances != null) {
606           for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
607             SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
608             JClassType syntheticThisType = (JClassType) typeMap.get(arg.type);
609             call.getArgs().add(createThisRef(info, syntheticThisType));
610           }
611         }
612         // Synthetic locals for local classes
613
if (nestedBinding.outerLocalVariables != null) {
614           for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
615             SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
616             JVariable variable = (JVariable) typeMap.get(arg.actualOuterLocalVariable);
617             call.getArgs().add(
618                 createVariableRef(info, variable, arg.actualOuterLocalVariable));
619           }
620         }
621       }
622
623       return call;
624     }
625
626     JExpression processExpression(AND_AND_Expression x) {
627       JType type = (JType) typeMap.get(x.resolvedType);
628       SourceInfo info = makeSourceInfo(x);
629       return processBinaryOperation(info, JBinaryOperator.AND, type, x.left,
630           x.right);
631     }
632
633     JExpression processExpression(ArrayAllocationExpression x) {
634       SourceInfo info = makeSourceInfo(x);
635       JArrayType type = (JArrayType) typeMap.get(x.resolvedType);
636       JNewArray newArray = new JNewArray(program, info, type);
637
638       if (x.initializer != null) {
639         newArray.initializers = new ArrayList JavaDoc();
640         if (x.initializer.expressions != null) {
641           for (int i = 0; i < x.initializer.expressions.length; i++) {
642             Expression expression = x.initializer.expressions[i];
643             newArray.initializers.add(dispProcessExpression(expression));
644           }
645         }
646       } else {
647         newArray.dims = new ArrayList JavaDoc();
648         for (int i = 0; i < x.dimensions.length; i++) {
649           Expression dimension = x.dimensions[i];
650           // can be null if index expression was empty
651
if (dimension == null) {
652             newArray.dims.add(program.getLiteralAbsentArrayDimension());
653           } else {
654             newArray.dims.add(dispProcessExpression(dimension));
655           }
656         }
657       }
658
659       return newArray;
660     }
661
662     JExpression processExpression(ArrayInitializer x) {
663       SourceInfo info = makeSourceInfo(x);
664       JArrayType type = (JArrayType) typeMap.get(x.resolvedType);
665       JNewArray newArray = new JNewArray(program, info, type);
666
667       newArray.initializers = new ArrayList JavaDoc();
668       if (x.expressions != null) {
669         for (int i = 0; i < x.expressions.length; i++) {
670           Expression expression = x.expressions[i];
671           newArray.initializers.add(dispProcessExpression(expression));
672         }
673       }
674
675       return newArray;
676     }
677
678     JExpression processExpression(ArrayReference x) {
679       SourceInfo info = makeSourceInfo(x);
680       JArrayRef arrayRef = new JArrayRef(program, info,
681           dispProcessExpression(x.receiver), dispProcessExpression(x.position));
682       return arrayRef;
683     }
684
685     JExpression processExpression(Assignment x) {
686       JType type = (JType) typeMap.get(x.resolvedType);
687       SourceInfo info = makeSourceInfo(x);
688       return processBinaryOperation(info, JBinaryOperator.ASG, type, x.lhs,
689           x.expression);
690     }
691
692     JExpression processExpression(BinaryExpression x) {
693       JBinaryOperator op;
694
695       int binOp = (x.bits & BinaryExpression.OperatorMASK) >> BinaryExpression.OperatorSHIFT;
696       switch (binOp) {
697         case BinaryExpression.LEFT_SHIFT:
698           op = JBinaryOperator.SHL;
699           break;
700         case BinaryExpression.RIGHT_SHIFT:
701           op = JBinaryOperator.SHR;
702           break;
703         case BinaryExpression.UNSIGNED_RIGHT_SHIFT:
704           op = JBinaryOperator.SHRU;
705           break;
706         case BinaryExpression.PLUS:
707           op = JBinaryOperator.ADD;
708           break;
709         case BinaryExpression.MINUS:
710           op = JBinaryOperator.SUB;
711           break;
712         case BinaryExpression.REMAINDER:
713           op = JBinaryOperator.MOD;
714           break;
715         case BinaryExpression.XOR:
716           op = JBinaryOperator.BIT_XOR;
717           break;
718         case BinaryExpression.AND:
719           op = JBinaryOperator.BIT_AND;
720           break;
721         case BinaryExpression.MULTIPLY:
722           op = JBinaryOperator.MUL;
723           break;
724         case BinaryExpression.OR:
725           op = JBinaryOperator.BIT_OR;
726           break;
727         case BinaryExpression.DIVIDE:
728           op = JBinaryOperator.DIV;
729           break;
730         case BinaryExpression.LESS_EQUAL:
731           op = JBinaryOperator.LTE;
732           break;
733         case BinaryExpression.GREATER_EQUAL:
734           op = JBinaryOperator.GTE;
735           break;
736         case BinaryExpression.GREATER:
737           op = JBinaryOperator.GT;
738           break;
739         case BinaryExpression.LESS:
740           op = JBinaryOperator.LT;
741           break;
742         default:
743           throw new InternalCompilerException(
744               "Unexpected operator for BinaryExpression");
745       }
746
747       JType type = (JType) typeMap.get(x.resolvedType);
748       SourceInfo info = makeSourceInfo(x);
749       return processBinaryOperation(info, op, type, x.left, x.right);
750     }
751
752     JExpression processExpression(CastExpression x) {
753       SourceInfo info = makeSourceInfo(x);
754       JType type = (JType) typeMap.get(x.resolvedType);
755       JCastOperation cast = new JCastOperation(program, info, type,
756           dispProcessExpression(x.expression));
757       return cast;
758     }
759
760     JExpression processExpression(ClassLiteralAccess x) {
761       JType type = (JType) typeMap.get(x.targetType);
762       return program.getLiteralClass(type);
763     }
764
765     JExpression processExpression(CompoundAssignment x) {
766       JBinaryOperator op;
767
768       switch (x.operator) {
769         case CompoundAssignment.PLUS:
770           op = JBinaryOperator.ASG_ADD;
771           break;
772         case CompoundAssignment.MINUS:
773           op = JBinaryOperator.ASG_SUB;
774           break;
775         case CompoundAssignment.MULTIPLY:
776           op = JBinaryOperator.ASG_MUL;
777           break;
778         case CompoundAssignment.DIVIDE:
779           op = JBinaryOperator.ASG_DIV;
780           break;
781         case CompoundAssignment.AND:
782           op = JBinaryOperator.ASG_BIT_AND;
783           break;
784         case CompoundAssignment.OR:
785           op = JBinaryOperator.ASG_BIT_OR;
786           break;
787         case CompoundAssignment.XOR:
788           op = JBinaryOperator.ASG_BIT_XOR;
789           break;
790         case CompoundAssignment.REMAINDER:
791           op = JBinaryOperator.ASG_MOD;
792           break;
793         case CompoundAssignment.LEFT_SHIFT:
794           op = JBinaryOperator.ASG_SHL;
795           break;
796         case CompoundAssignment.RIGHT_SHIFT:
797           op = JBinaryOperator.ASG_SHR;
798           break;
799         case CompoundAssignment.UNSIGNED_RIGHT_SHIFT:
800           op = JBinaryOperator.ASG_SHRU;
801           break;
802         default:
803           throw new InternalCompilerException(
804               "Unexpected operator for CompoundAssignment");
805       }
806
807       JType type = (JType) typeMap.get(x.resolvedType);
808       SourceInfo info = makeSourceInfo(x);
809       return processBinaryOperation(info, op, type, x.lhs, x.expression);
810     }
811
812     JExpression processExpression(ConditionalExpression x) {
813       SourceInfo info = makeSourceInfo(x);
814       JType type = (JType) typeMap.get(x.resolvedType);
815       JExpression ifTest = dispProcessExpression(x.condition);
816       JExpression thenExpr = dispProcessExpression(x.valueIfTrue);
817       JExpression elseExpr = dispProcessExpression(x.valueIfFalse);
818       JConditional conditional = new JConditional(program, info, type, ifTest,
819           thenExpr, elseExpr);
820       return conditional;
821     }
822
823     JExpression processExpression(EqualExpression x) {
824       JBinaryOperator op;
825       switch ((x.bits & BinaryExpression.OperatorMASK) >> BinaryExpression.OperatorSHIFT) {
826         case BinaryExpression.EQUAL_EQUAL:
827           op = JBinaryOperator.EQ;
828           break;
829         case BinaryExpression.NOT_EQUAL:
830           op = JBinaryOperator.NEQ;
831           break;
832         default:
833           throw new InternalCompilerException(
834               "Unexpected operator for EqualExpression");
835       }
836
837       JType type = (JType) typeMap.get(x.resolvedType);
838       SourceInfo info = makeSourceInfo(x);
839       return processBinaryOperation(info, op, type, x.left, x.right);
840     }
841
842     /**
843      * How we have to treat super calls vs. this calls is so different, they may
844      * as well have been two different JDT nodes.
845      */

846     JMethodCall processExpression(ExplicitConstructorCall x) {
847       if (x.isSuperAccess()) {
848         return processSuperConstructorCall(x);
849       } else {
850         return processThisConstructorCall(x);
851       }
852     }
853
854     JExpression processExpression(FieldReference x) {
855       SourceInfo info = makeSourceInfo(x);
856       FieldBinding fieldBinding = x.binding;
857       JField field;
858       if (fieldBinding.declaringClass == null) {
859         // probably array.length
860
field = program.getSpecialField("Array.length");
861         if (!field.getName().equals(String.valueOf(fieldBinding.name))) {
862           throw new InternalCompilerException("Error matching fieldBinding.");
863         }
864       } else {
865         field = (JField) typeMap.get(fieldBinding);
866       }
867       JExpression instance = dispProcessExpression(x.receiver);
868       JExpression fieldRef = new JFieldRef(program, info, instance, field,
869           currentClass);
870       return fieldRef;
871     }
872
873     JExpression processExpression(InstanceOfExpression x) {
874       SourceInfo info = makeSourceInfo(x);
875       JExpression expr = dispProcessExpression(x.expression);
876       JReferenceType testType = (JReferenceType) typeMap.get(x.type.resolvedType);
877       return new JInstanceOf(program, info, testType, expr);
878     }
879
880     JExpression processExpression(MessageSend x) {
881       SourceInfo info = makeSourceInfo(x);
882       JType type = (JType) typeMap.get(x.resolvedType);
883       JMethod method = (JMethod) typeMap.get(x.binding);
884       assert (type == method.getType());
885
886       JExpression qualifier;
887       if (x.receiver instanceof ThisReference) {
888         if (method.isStatic()) {
889           // don't bother qualifying it, it's a no-op
890
qualifier = null;
891         } else if (x.receiver instanceof QualifiedThisReference) {
892           // use the supplied qualifier
893
qualifier = dispProcessExpression(x.receiver);
894         } else {
895           /*
896            * In cases where JDT had to synthesize a this ref for us, it could
897            * actually be the wrong type, if the target method is in an enclosing
898            * class. We have to sythensize our own ref of the correct type.
899            */

900           qualifier = createThisRef(info, method.getEnclosingType());
901         }
902       } else {
903         qualifier = dispProcessExpression(x.receiver);
904       }
905
906       JMethodCall call = new JMethodCall(program, info, qualifier, method);
907
908       // On a super ref, don't allow polymorphic dispatch. Oddly enough,
909
// QualifiedSuperReference not derived from SuperReference!
910
boolean isSuperRef = x.receiver instanceof SuperReference
911           || x.receiver instanceof QualifiedSuperReference;
912       if (isSuperRef) {
913         call.setStaticDispatchOnly();
914       }
915
916       // The arguments come first...
917
if (x.arguments != null) {
918         for (int i = 0, n = x.arguments.length; i < n; ++i) {
919           call.getArgs().add(dispProcessExpression(x.arguments[i]));
920         }
921       }
922
923       return call;
924     }
925
926     JExpression processExpression(NullLiteral x) {
927       return program.getLiteralNull();
928     }
929
930     JExpression processExpression(OR_OR_Expression x) {
931       JType type = (JType) typeMap.get(x.resolvedType);
932       SourceInfo info = makeSourceInfo(x);
933       return processBinaryOperation(info, JBinaryOperator.OR, type, x.left,
934           x.right);
935     }
936
937     JExpression processExpression(PostfixExpression x) {
938       SourceInfo info = makeSourceInfo(x);
939       JUnaryOperator op;
940
941       switch (x.operator) {
942         case PostfixExpression.MINUS:
943           op = JUnaryOperator.DEC;
944           break;
945
946         case PostfixExpression.PLUS:
947           op = JUnaryOperator.INC;
948           break;
949
950         default:
951           throw new InternalCompilerException("Unexpected postfix operator");
952       }
953
954       JPostfixOperation postOp = new JPostfixOperation(program, info, op,
955           dispProcessExpression(x.lhs));
956       return postOp;
957     }
958
959     JExpression processExpression(PrefixExpression x) {
960       SourceInfo info = makeSourceInfo(x);
961       JUnaryOperator op;
962
963       switch (x.operator) {
964         case PrefixExpression.MINUS:
965           op = JUnaryOperator.DEC;
966           break;
967
968         case PrefixExpression.PLUS:
969           op = JUnaryOperator.INC;
970           break;
971
972         default:
973           throw new InternalCompilerException("Unexpected prefix operator");
974       }
975
976       JPrefixOperation preOp = new JPrefixOperation(program, info, op,
977           dispProcessExpression(x.lhs));
978       return preOp;
979     }
980
981     JExpression processExpression(QualifiedAllocationExpression x) {
982       /*
983        * Weird: sometimes JDT will create a QualifiedAllocationExpression with
984        * no qualifier. I guess this is supposed to let us know that we need to
985        * synthesize a synthetic this arg based on our own current "this"? But
986        * plain old regular AllocationExpression also must be treated as if it
987        * might be be implicitly qualified, so I'm not sure what the point is.
988        * Let's just defer to the AllocationExpression logic if there's no
989        * qualifier.
990        */

991       if (x.enclosingInstance() == null) {
992         return processExpression((AllocationExpression) x);
993       }
994
995       SourceInfo info = makeSourceInfo(x);
996       MethodBinding b = x.binding;
997       JMethod ctor = (JMethod) typeMap.get(b);
998       JClassType enclosingType = (JClassType) ctor.getEnclosingType();
999       JNewInstance newInstance = new JNewInstance(program, info, enclosingType);
1000      JMethodCall call = new JMethodCall(program, info, newInstance, ctor);
1001      JExpression qualifier = dispProcessExpression(x.enclosingInstance);
1002      List JavaDoc qualList = new ArrayList JavaDoc();
1003      qualList.add(qualifier);
1004
1005      /*
1006       * Really weird: Sometimes an allocation expression needs both its
1007       * explicit qualifier AND its implicit enclosing class! We add this second
1008       * because the explicit qualifier takes precedence.
1009       */

1010      if (!currentMethod.isStatic()) {
1011        JExpression implicitOuter = program.getExprThisRef(info,
1012            (JClassType) currentClass);
1013        qualList.add(implicitOuter);
1014      }
1015
1016      // Plain old regular arguments
1017
if (x.arguments != null) {
1018        for (int i = 0, n = x.arguments.length; i < n; ++i) {
1019          call.getArgs().add(dispProcessExpression(x.arguments[i]));
1020        }
1021      }
1022
1023      // Synthetic args for inner classes
1024
ReferenceBinding targetBinding = b.declaringClass;
1025      if (targetBinding.isNestedType() && !targetBinding.isStatic()) {
1026        NestedTypeBinding nestedBinding = (NestedTypeBinding) targetBinding;
1027        // Synthetic this args for inner classes
1028
if (nestedBinding.enclosingInstances != null) {
1029          for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
1030            SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
1031            JClassType syntheticThisType = (JClassType) typeMap.get(arg.type);
1032            call.getArgs().add(createThisRef(syntheticThisType, qualList));
1033          }
1034        }
1035        // Synthetic locals for local classes
1036
if (nestedBinding.outerLocalVariables != null) {
1037          for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
1038            SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
1039            JVariable variable = (JVariable) typeMap.get(arg.actualOuterLocalVariable);
1040            call.getArgs().add(
1041                createVariableRef(info, variable, arg.actualOuterLocalVariable));
1042          }
1043        }
1044      }
1045
1046      return call;
1047    }
1048
1049    JExpression processExpression(QualifiedNameReference x) {
1050      SourceInfo info = makeSourceInfo(x);
1051      Binding binding = x.binding;
1052      JNode node = typeMap.get(binding);
1053      if (!(node instanceof JVariable)) {
1054        return null;
1055      }
1056      JVariable variable = (JVariable) node;
1057
1058      JExpression curRef = createVariableRef(info, variable, binding);
1059
1060      /*
1061       * Wackiness: JDT represents multiple field access as an array of fields,
1062       * each qualified by everything to the left. So each subsequent item in
1063       * otherBindings takes the current expression as a qualifier.
1064       */

1065      if (x.otherBindings != null) {
1066        for (int i = 0; i < x.otherBindings.length; i++) {
1067          FieldBinding fieldBinding = x.otherBindings[i];
1068          JField field;
1069          if (fieldBinding.declaringClass == null) {
1070            // probably array.length
1071
field = program.getSpecialField("Array.length");
1072            if (!field.getName().equals(String.valueOf(fieldBinding.name))) {
1073              throw new InternalCompilerException(
1074                  "Error matching fieldBinding.");
1075            }
1076          } else {
1077            field = (JField) typeMap.get(fieldBinding);
1078          }
1079          curRef = new JFieldRef(program, info, curRef, field, currentClass);
1080        }
1081      }
1082
1083      return curRef;
1084    }
1085
1086    JExpression processExpression(QualifiedSuperReference x) {
1087      JClassType refType = (JClassType) typeMap.get(x.resolvedType);
1088      JClassType qualType = (JClassType) typeMap.get(x.qualification.resolvedType);
1089      assert (refType == qualType.extnds);
1090      // Oddly enough, super refs can be modeled as this refs, because whatever
1091
// expression they qualify has already been resolved.
1092
return processQualifiedThisOrSuperRef(x, qualType);
1093    }
1094
1095    JExpression processExpression(QualifiedThisReference x) {
1096      JClassType refType = (JClassType) typeMap.get(x.resolvedType);
1097      JClassType qualType = (JClassType) typeMap.get(x.qualification.resolvedType);
1098      assert (refType == qualType);
1099      return processQualifiedThisOrSuperRef(x, qualType);
1100    }
1101
1102    JExpression processExpression(SingleNameReference x) {
1103      SourceInfo info = makeSourceInfo(x);
1104      Binding binding = x.binding;
1105      Object JavaDoc target = typeMap.get(binding);
1106      if (!(target instanceof JVariable)) {
1107        return null;
1108      }
1109      JVariable variable = (JVariable) target;
1110
1111      /*
1112       * Wackiness: if a field happens to have synthetic accessors (only fields
1113       * can have them, apparently), this is a ref to a field in an enclosing
1114       * instance. CreateThisRef should compute a "this" access of the
1115       * appropriate type, unless the field is static.
1116       */

1117      if (x.syntheticAccessors != null) {
1118        JField field = (JField) variable;
1119        if (!field.isStatic()) {
1120          JExpression instance = createThisRef(info, field.getEnclosingType());
1121          return new JFieldRef(program, info, instance, field, currentClass);
1122        }
1123      }
1124
1125      return createVariableRef(info, variable, binding);
1126    }
1127
1128    JExpression processExpression(SuperReference x) {
1129      JClassType type = (JClassType) typeMap.get(x.resolvedType);
1130      assert (type == currentClass.extnds);
1131      SourceInfo info = makeSourceInfo(x);
1132      // Oddly enough, super refs can be modeled as a this refs.
1133
JExpression superRef = createThisRef(info, currentClass);
1134      return superRef;
1135    }
1136
1137    JExpression processExpression(ThisReference x) {
1138      JClassType type = (JClassType) typeMap.get(x.resolvedType);
1139      assert (type == currentClass);
1140      SourceInfo info = makeSourceInfo(x);
1141      JExpression thisRef = createThisRef(info, currentClass);
1142      return thisRef;
1143    }
1144
1145    JExpression processExpression(UnaryExpression x) {
1146      SourceInfo info = makeSourceInfo(x);
1147      JUnaryOperator op;
1148      int operator = ((x.bits & UnaryExpression.OperatorMASK) >> UnaryExpression.OperatorSHIFT);
1149
1150      switch (operator) {
1151        case UnaryExpression.MINUS:
1152          op = JUnaryOperator.NEG;
1153          break;
1154
1155        case UnaryExpression.NOT:
1156          op = JUnaryOperator.NOT;
1157          break;
1158
1159        case UnaryExpression.PLUS:
1160          // Odd case.. a useless + operator; just return the operand
1161
return dispProcessExpression(x.expression);
1162
1163        case UnaryExpression.TWIDDLE:
1164          op = JUnaryOperator.BIT_NOT;
1165          break;
1166
1167        default:
1168          throw new InternalCompilerException(
1169              "Unexpected operator for unary expression");
1170      }
1171
1172      JPrefixOperation preOp = new JPrefixOperation(program, info, op,
1173          dispProcessExpression(x.expression));
1174      return preOp;
1175    }
1176
1177    void processField(FieldDeclaration declaration) {
1178      JField field = (JField) typeMap.tryGet(declaration.binding);
1179      if (field == null) {
1180        /*
1181         * When anonymous classes declare constant fields, the field declaration
1182         * is not visited by JDT. Just bail since any references to that field
1183         * are guaranteed to be replaced with literals.
1184         */

1185        return;
1186      }
1187      try {
1188        JExpression initializer = null;
1189        if (declaration.initialization != null) {
1190          initializer = dispProcessExpression(declaration.initialization);
1191        }
1192
1193        if (initializer instanceof JLiteral) {
1194          field.constInitializer = (JLiteral) initializer;
1195        } else if (initializer != null) {
1196          SourceInfo info = makeSourceInfo(declaration);
1197          JStatement assignStmt = program.createAssignmentStmt(info,
1198              createVariableRef(info, field), initializer);
1199
1200          // will either be init or clinit
1201
currentMethod.body.statements.add(assignStmt);
1202        }
1203      } catch (Throwable JavaDoc e) {
1204        throw translateException(field, e);
1205      }
1206    }
1207
1208    void processInitializer(Initializer initializer) {
1209      JBlock block = (JBlock) dispProcessStatement(initializer.block);
1210      try {
1211        // will either be init or clinit
1212
currentMethod.body.statements.add(block);
1213      } catch (Throwable JavaDoc e) {
1214        throw translateException(initializer, e);
1215      }
1216    }
1217
1218    void processMethod(AbstractMethodDeclaration x) {
1219      MethodBinding b = x.binding;
1220      JMethod method = (JMethod) typeMap.get(b);
1221      try {
1222        if (b.isImplementing() || b.isOverriding()) {
1223          tryFindUpRefs(method, b);
1224        }
1225
1226        if (x.isNative()) {
1227          processNativeMethod(x, (JsniMethod) method);
1228          return;
1229        }
1230
1231        currentMethod = method;
1232        currentMethodScope = x.scope;
1233
1234        if (x.statements != null) {
1235          for (int i = 0, n = x.statements.length; i < n; ++i) {
1236            Statement origStmt = x.statements[i];
1237            JStatement jstmt = dispProcessStatement(origStmt);
1238            if (jstmt != null) {
1239              method.body.statements.add(jstmt);
1240            }
1241          }
1242        }
1243        currentMethodScope = null;
1244        currentMethod = null;
1245      } catch (Throwable JavaDoc e) {
1246        throw translateException(method, e);
1247      }
1248    }
1249
1250    void processNativeMethod(AbstractMethodDeclaration x,
1251        JsniMethod nativeMethod) {
1252
1253      JsFunction func = nativeMethod.getFunc();
1254      if (func == null) {
1255        return;
1256      }
1257
1258      // resolve jsni refs
1259
final List JavaDoc/* <JsNameRef> */nameRefs = new ArrayList JavaDoc/* <JsNameRef> */();
1260      new JsVisitor() {
1261        // @Override
1262
public void endVisit(JsNameRef x, JsContext ctx) {
1263          String JavaDoc ident = x.getIdent();
1264          if (ident.charAt(0) == '@') {
1265            nameRefs.add(x);
1266          }
1267        }
1268      }.accept(func);
1269
1270      for (int i = 0; i < nameRefs.size(); ++i) {
1271        JsNameRef nameRef = (JsNameRef) nameRefs.get(i);
1272        SourceInfo info = nativeMethod.getSourceInfo();
1273        // TODO: make this tighter when we have real source info
1274
// JSourceInfo info = translateInfo(nameRef.getInfo());
1275
String JavaDoc ident = nameRef.getIdent();
1276        HasEnclosingType node = (HasEnclosingType) program.jsniMap.get(ident);
1277        if (node == null) {
1278          node = parseJsniRef(info, x, ident);
1279          if (node == null) {
1280            continue; // already reported error
1281
}
1282          program.jsniMap.put(ident, node);
1283        }
1284        assert (node != null);
1285        CanBeStatic canBeStatic = (CanBeStatic) node;
1286        HasName hasName = (HasName) node;
1287        boolean isField = node instanceof JField;
1288        assert (isField || node instanceof JMethod);
1289        if (canBeStatic.isStatic() && nameRef.getQualifier() != null) {
1290          reportJsniError(info, x,
1291              "Cannot make a qualified reference to the static "
1292                  + (isField ? "field " : "method ") + hasName.getName());
1293        } else if (!canBeStatic.isStatic() && nameRef.getQualifier() == null) {
1294          reportJsniError(info, x,
1295              "Cannot make an unqualified reference to the instance "
1296                  + (isField ? "field " : "method ") + hasName.getName());
1297        }
1298
1299        if (isField) {
1300          /*
1301           * TODO FIXME HACK: We should be replacing compile-time constant refs
1302           * from JSNI with the literal value of the field.
1303           */

1304          JField field = (JField) node;
1305          JsniFieldRef fieldRef = new JsniFieldRef(program, info, field,
1306              currentClass);
1307          nativeMethod.jsniFieldRefs.add(fieldRef);
1308        } else {
1309          JMethod method = (JMethod) node;
1310          JsniMethodRef methodRef = new JsniMethodRef(program, info, method);
1311          nativeMethod.jsniMethodRefs.add(methodRef);
1312        }
1313      }
1314    }
1315
1316    JStatement processStatement(AssertStatement x) {
1317      SourceInfo info = makeSourceInfo(x);
1318      JExpression expr = dispProcessExpression(x.assertExpression);
1319      JExpression arg = dispProcessExpression(x.exceptionArgument);
1320      return new JAssertStatement(program, info, expr, arg);
1321    }
1322
1323    // // 5.0
1324
// JStatement processStatement(ForeachStatement x) {
1325
// return null;
1326
// }
1327

1328    JBlock processStatement(Block x) {
1329      if (x == null) {
1330        return null;
1331      }
1332
1333      SourceInfo info = makeSourceInfo(x);
1334      JBlock block = new JBlock(program, info);
1335      if (x.statements != null) {
1336        for (int i = 0, n = x.statements.length; i < n; ++i) {
1337          JStatement jstmt = dispProcessStatement(x.statements[i]);
1338          if (jstmt != null) {
1339            block.statements.add(jstmt);
1340          }
1341        }
1342      }
1343      return block;
1344    }
1345
1346    JStatement processStatement(BreakStatement x) {
1347      SourceInfo info = makeSourceInfo(x);
1348      return new JBreakStatement(program, info, getOrCreateLabel(info,
1349          currentMethod, x.label));
1350    }
1351
1352    JStatement processStatement(CaseStatement x) {
1353      SourceInfo info = makeSourceInfo(x);
1354      JExpression expression = dispProcessExpression(x.constantExpression);
1355      return new JCaseStatement(program, info, (JLiteral) expression);
1356    }
1357
1358    JStatement processStatement(ContinueStatement x) {
1359      SourceInfo info = makeSourceInfo(x);
1360      return new JContinueStatement(program, info, getOrCreateLabel(info,
1361          currentMethod, x.label));
1362    }
1363
1364    JStatement processStatement(DoStatement x) {
1365      SourceInfo info = makeSourceInfo(x);
1366      JExpression loopTest = dispProcessExpression(x.condition);
1367      JStatement loopBody = dispProcessStatement(x.action);
1368      JDoStatement stmt = new JDoStatement(program, info, loopTest, loopBody);
1369      return stmt;
1370    }
1371
1372    JStatement processStatement(EmptyStatement x) {
1373      return null;
1374    }
1375
1376    JStatement processStatement(ForStatement x) {
1377      SourceInfo info = makeSourceInfo(x);
1378      // SEE NOTE ON JDT FORCED OPTIMIZATIONS
1379
// If the condition is false, don't process the body
1380
boolean removeBody = isOptimizedFalse(x.condition);
1381
1382      List JavaDoc/* <? extends JStatement> */init = processStatements(x.initializations);
1383      JExpression expr = dispProcessExpression(x.condition);
1384      List JavaDoc/* <JExpressionStatement> */incr = processStatements(x.increments);
1385      JStatement body = removeBody ? null : dispProcessStatement(x.action);
1386      return new JForStatement(program, info, init, expr, incr, body);
1387    }
1388
1389    JStatement processStatement(IfStatement x) {
1390      // SEE NOTE ON JDT FORCED OPTIMIZATIONS
1391
// If the condition is false, don't process the then statement
1392
// If the condition is false, don't process the else statement
1393
boolean removeThen = isOptimizedFalse(x.condition);
1394      boolean removeElse = isOptimizedTrue(x.condition);
1395
1396      SourceInfo info = makeSourceInfo(x);
1397      JExpression expr = dispProcessExpression(x.condition);
1398      JStatement thenStmt = removeThen ? null
1399          : dispProcessStatement(x.thenStatement);
1400      JStatement elseStmt = removeElse ? null
1401          : dispProcessStatement(x.elseStatement);
1402      JIfStatement ifStmt = new JIfStatement(program, info, expr, thenStmt,
1403          elseStmt);
1404      return ifStmt;
1405    }
1406
1407    JStatement processStatement(LabeledStatement x) {
1408      JStatement body = dispProcessStatement(x.statement);
1409      if (body == null) {
1410        return null;
1411      }
1412      SourceInfo info = makeSourceInfo(x);
1413      return new JLabeledStatement(program, info, getOrCreateLabel(info,
1414          currentMethod, x.label), body);
1415    }
1416
1417    JStatement processStatement(LocalDeclaration x) {
1418      SourceInfo info = makeSourceInfo(x);
1419      JLocal local = (JLocal) typeMap.get(x.binding);
1420      JLocalRef localRef = new JLocalRef(program, info, local);
1421      JExpression initializer = dispProcessExpression(x.initialization);
1422      return new JLocalDeclarationStatement(program, info, localRef,
1423          initializer);
1424    }
1425
1426    JStatement processStatement(ReturnStatement x) {
1427      SourceInfo info = makeSourceInfo(x);
1428      if (currentMethodScope.referenceContext instanceof ConstructorDeclaration) {
1429        /*
1430         * Special: constructors are implemented as instance methods that return
1431         * their this object, so any embedded return statements have to be fixed
1432         * up.
1433         */

1434        JClassType enclosingType = (JClassType) currentMethod.getEnclosingType();
1435        assert (x.expression == null);
1436        return new JReturnStatement(program, info, createThisRef(info,
1437            enclosingType));
1438      } else {
1439        return new JReturnStatement(program, info,
1440            dispProcessExpression(x.expression));
1441      }
1442    }
1443
1444    JStatement processStatement(SwitchStatement x) {
1445      SourceInfo info = makeSourceInfo(x);
1446      JExpression expression = dispProcessExpression(x.expression);
1447      JBlock block = new JBlock(program, info);
1448      block.statements = processStatements(x.statements);
1449      return new JSwitchStatement(program, info, expression, block);
1450    }
1451
1452    JStatement processStatement(SynchronizedStatement x) {
1453      SourceInfo info = makeSourceInfo(x);
1454      JBlock block = (JBlock) dispProcessStatement(x.block);
1455      JExpression expr = dispProcessExpression(x.expression);
1456      block.statements.add(0, expr.makeStatement());
1457      return block;
1458    }
1459
1460    JStatement processStatement(ThrowStatement x) {
1461      SourceInfo info = makeSourceInfo(x);
1462      JExpression toThrow = dispProcessExpression(x.exception);
1463      return new JThrowStatement(program, info, toThrow);
1464    }
1465
1466    JStatement processStatement(TryStatement x) {
1467      SourceInfo info = makeSourceInfo(x);
1468      JBlock tryBlock = (JBlock) dispProcessStatement(x.tryBlock);
1469      List JavaDoc/* <JLocalRef> */catchArgs = new ArrayList JavaDoc/* <JLocalRef> */();
1470      List JavaDoc/* <JBlock> */catchBlocks = new ArrayList JavaDoc/* <JBlock> */();
1471      if (x.catchBlocks != null) {
1472        for (int i = 0, c = x.catchArguments.length; i < c; ++i) {
1473          JLocal local = (JLocal) typeMap.get(x.catchArguments[i].binding);
1474          catchArgs.add(createVariableRef(info, local));
1475        }
1476        for (int i = 0, c = x.catchBlocks.length; i < c; ++i) {
1477          catchBlocks.add(dispProcessStatement(x.catchBlocks[i]));
1478        }
1479      }
1480      JBlock finallyBlock = (JBlock) dispProcessStatement(x.finallyBlock);
1481      return new JTryStatement(program, info, tryBlock, catchArgs, catchBlocks,
1482          finallyBlock);
1483    }
1484
1485    JStatement processStatement(TypeDeclaration x) {
1486      // do nothing -- the local class is treated at the program level
1487
return null;
1488    }
1489
1490    JStatement processStatement(WhileStatement x) {
1491      // SEE NOTE ON JDT FORCED OPTIMIZATIONS
1492
// If the condition is false, don't process the body
1493
boolean removeBody = isOptimizedFalse(x.condition);
1494
1495      SourceInfo info = makeSourceInfo(x);
1496      JExpression loopTest = dispProcessExpression(x.condition);
1497      JStatement loopBody = removeBody ? null : dispProcessStatement(x.action);
1498      JWhileStatement stmt = new JWhileStatement(program, info, loopTest,
1499          loopBody);
1500      return stmt;
1501    }
1502
1503    List JavaDoc/* <? extends JStatement> */processStatements(Statement[] statements) {
1504      List JavaDoc/* <JStatement> */jstatements = new ArrayList JavaDoc/* <JStatement> */();
1505      if (statements != null) {
1506        for (int i = 0, n = statements.length; i < n; ++i) {
1507          JStatement jstmt = dispProcessStatement(statements[i]);
1508          if (jstmt != null) {
1509            jstatements.add(jstmt);
1510          }
1511        }
1512      }
1513      return jstatements;
1514    }
1515
1516    JMethodCall processSuperConstructorCall(ExplicitConstructorCall x) {
1517      SourceInfo info = makeSourceInfo(x);
1518      JMethod ctor = (JMethod) typeMap.get(x.binding);
1519      JExpression trueQualifier = createThisRef(info, currentClass);
1520      JMethodCall call = new JMethodCall(program, info, trueQualifier, ctor);
1521
1522      if (x.arguments != null) {
1523        for (int i = 0, n = x.arguments.length; i < n; ++i) {
1524          call.getArgs().add(dispProcessExpression(x.arguments[i]));
1525        }
1526      }
1527
1528      // We have to find and pass through any synthetics our supertype needs
1529
ReferenceBinding superClass = x.binding.declaringClass;
1530      if (superClass instanceof NestedTypeBinding && !superClass.isStatic()) {
1531        NestedTypeBinding myBinding = (NestedTypeBinding) currentClassScope.referenceType().binding;
1532        NestedTypeBinding superBinding = (NestedTypeBinding) superClass;
1533
1534        // enclosing types
1535
if (superBinding.enclosingInstances != null) {
1536          JExpression qualifier = dispProcessExpression(x.qualification);
1537          for (int j = 0; j < superBinding.enclosingInstances.length; ++j) {
1538            SyntheticArgumentBinding arg = superBinding.enclosingInstances[j];
1539            JClassType classType = (JClassType) typeMap.get(arg.type);
1540            if (qualifier == null) {
1541              /*
1542               * Got to be one of my params; it would be illegal to use a this
1543               * ref at this moment-- we would most likely be passing in a
1544               * supertype field that HASN'T BEEN INITIALIZED YET.
1545               *
1546               * Unfortunately, my params might not work as-is, so we have to
1547               * check each one to see if any will make a suitable this ref.
1548               */

1549              List JavaDoc/* <JExpression> */workList = new ArrayList JavaDoc/* <JExpression> */();
1550              Iterator JavaDoc/* <JParameter> */paramIt = getSyntheticsIterator(currentMethod);
1551              for (int i = 0; i < myBinding.enclosingInstances.length; ++i) {
1552                workList.add(createVariableRef(info,
1553                    (JParameter) paramIt.next()));
1554              }
1555              call.getArgs().add(createThisRef(classType, workList));
1556            } else {
1557              call.getArgs().add(createThisRef(classType, qualifier));
1558            }
1559          }
1560        }
1561
1562        // outer locals
1563
if (superBinding.outerLocalVariables != null) {
1564          for (int j = 0; j < superBinding.outerLocalVariables.length; ++j) {
1565            SyntheticArgumentBinding arg = superBinding.outerLocalVariables[j];
1566            // Got to be one of my params
1567
JType varType = (JType) typeMap.get(arg.type);
1568            String JavaDoc varName = String.valueOf(arg.name);
1569            JParameter param = null;
1570            for (int i = 0; i < currentMethod.params.size(); ++i) {
1571              JParameter paramIt = (JParameter) currentMethod.params.get(i);
1572              if (varType == paramIt.getType()
1573                  && varName.equals(paramIt.getName())) {
1574                param = paramIt;
1575              }
1576            }
1577            if (param == null) {
1578              throw new InternalCompilerException(
1579                  "Could not find matching local arg for explicit super ctor call.");
1580            }
1581            call.getArgs().add(createVariableRef(info, param));
1582          }
1583        }
1584      }
1585
1586      return call;
1587    }
1588
1589    JMethodCall processThisConstructorCall(ExplicitConstructorCall x) {
1590      SourceInfo info = makeSourceInfo(x);
1591      JMethod ctor = (JMethod) typeMap.get(x.binding);
1592      JExpression trueQualifier = createThisRef(info, currentClass);
1593      JMethodCall call = new JMethodCall(program, info, trueQualifier, ctor);
1594
1595      assert (x.qualification == null);
1596
1597      if (x.arguments != null) {
1598        for (int i = 0, n = x.arguments.length; i < n; ++i) {
1599          call.getArgs().add(dispProcessExpression(x.arguments[i]));
1600        }
1601      }
1602
1603      // All synthetics must be passed through to the target ctor
1604
ReferenceBinding declaringClass = x.binding.declaringClass;
1605      if (declaringClass instanceof NestedTypeBinding) {
1606        Iterator JavaDoc/* <JParameter> */paramIt = getSyntheticsIterator(currentMethod);
1607        NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
1608        if (nestedBinding.enclosingInstances != null) {
1609          for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
1610            call.getArgs().add(
1611                createVariableRef(info, (JParameter) paramIt.next()));
1612          }
1613        }
1614        if (nestedBinding.outerLocalVariables != null) {
1615          for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
1616            call.getArgs().add(
1617                createVariableRef(info, (JParameter) paramIt.next()));
1618          }
1619        }
1620      }
1621
1622      return call;
1623    }
1624
1625    private void addAllOuterThisRefs(List JavaDoc list, JExpression expr,
1626        JClassType classType) {
1627      if (classType.fields.size() > 0) {
1628        JField field = (JField) classType.fields.get(0);
1629        if (field.getName().startsWith("this$")) {
1630          list.add(new JFieldRef(program, expr.getSourceInfo(), expr, field,
1631              currentClass));
1632        }
1633      }
1634    }
1635
1636    private void addAllOuterThisRefsPlusSuperChain(List JavaDoc workList,
1637        JExpression expr, JClassType classType) {
1638      for (; classType != null; classType = classType.extnds) {
1639        addAllOuterThisRefs(workList, expr, classType);
1640      }
1641    }
1642
1643    private boolean areParametersIdentical(MethodBinding a, MethodBinding b) {
1644      TypeBinding[] params1 = a.parameters;
1645      TypeBinding[] params2 = b.parameters;
1646      if (params1.length != params2.length) {
1647        return false;
1648      }
1649
1650      for (int i = 0; i < params1.length; ++i) {
1651        if (params1[i] != params2[i]) {
1652          return false;
1653        }
1654      }
1655
1656      return true;
1657    }
1658
1659    /**
1660     * Helper to create a qualified "this" ref (really a synthetic this field
1661     * access) of the appropriate type. Always use this method instead of
1662     * creating a naked JThisRef or you won't get the synthetic accesses right.
1663     */

1664    private JExpression createQualifiedThisRef(SourceInfo info,
1665        JClassType targetType) {
1666      assert (currentClass instanceof JClassType);
1667      JExpression expr = program.getExprThisRef(info, (JClassType) currentClass);
1668      List JavaDoc/* <JExpression> */list = new ArrayList JavaDoc();
1669      addAllOuterThisRefsPlusSuperChain(list, expr, (JClassType) currentClass);
1670      return createThisRef(targetType, list);
1671    }
1672
1673    /**
1674     * Helper to create an expression of the target type, possibly by accessing
1675     * synthetic this fields on the passed-in expression. This is needed by a
1676     * QualifiedAllocationExpression, because the qualifier may not be the
1677     * correct type, and we may need use one of its fields.
1678     */

1679    private JExpression createThisRef(JReferenceType qualType, JExpression expr) {
1680      List JavaDoc/* <JExpression> */list = new ArrayList JavaDoc();
1681      list.add(expr);
1682      return createThisRef(qualType, list);
1683    }
1684
1685    /**
1686     * Helper to create an expression of the target type, possibly by accessing
1687     * synthetic this fields on ANY of several passed-in expressions. Why in the
1688     * world would we need to do this? It turns out that when making an
1689     * unqualified explicit super constructor call to something that needs a
1690     * synthetic outer this arg, the correct value to pass in can be one of
1691     * several of the calling constructor's own synthetic ags. The catch is,
1692     * it's possible none of the args are exactly the right type-- we have to
1693     * make one of them the right type by following each of their synthetic this
1694     * refs up an arbitrarily big tree of enclosing classes and
1695     * supertypes-with-enclosing-classes until we find something that's the
1696     * right type.
1697     *
1698     * We have this implemented as a Breadth-First Search to minimize the number
1699     * of derefs required, and this seems to be correct. Note that we explicitly
1700     * prefer the current expression as one of its supertypes over a synthetic
1701     * this ref rooted off the current expression that happens to be the correct
1702     * type. We have observed this to be consistent with how Java handles it.
1703     */

1704    private JExpression createThisRef(JReferenceType qualType,
1705        List JavaDoc/* <JExpression> */list) {
1706      LinkedList JavaDoc/* <JExpression> */workList = new LinkedList JavaDoc/* <JExpression> */();
1707      workList.addAll(list);
1708      while (!workList.isEmpty()) {
1709        JExpression expr = (JExpression) workList.removeFirst();
1710        JClassType classType = (JClassType) expr.getType();
1711        for (; classType != null; classType = classType.extnds) {
1712          // prefer myself or myself-as-supertype over any of my this$ fields
1713
// that may have already been added to the work list
1714
if (program.typeOracle.canTriviallyCast(classType, qualType)) {
1715            return expr;
1716          }
1717          addAllOuterThisRefs(workList, expr, classType);
1718        }
1719      }
1720
1721      throw new InternalCompilerException(
1722          "Cannot create a ThisRef of the appropriate type.");
1723    }
1724
1725    /**
1726     * Helper to creates this ref (or maybe a synthetic this field access) of
1727     * the appropriate type. Always use this method instead of creating a naked
1728     * JThisRef or you won't get the synthetic accesses right.
1729     */

1730    private JExpression createThisRef(SourceInfo info, JReferenceType targetType) {
1731      assert (currentClass instanceof JClassType);
1732      return createThisRef(targetType, program.getExprThisRef(info,
1733          (JClassType) currentClass));
1734    }
1735
1736    /**
1737     * Creates an appropriate JVariableRef for the polymorphic type of the
1738     * requested JVariable.
1739     */

1740    private JVariableRef createVariableRef(SourceInfo info, JVariable variable) {
1741      if (variable instanceof JLocal) {
1742        JLocal local = (JLocal) variable;
1743        if (local.getEnclosingMethod() != currentMethod) {
1744          throw new InternalCompilerException(
1745              "LocalRef referencing local in a different method.");
1746        }
1747        return new JLocalRef(program, info, local);
1748      } else if (variable instanceof JParameter) {
1749        JParameter parameter = (JParameter) variable;
1750        if (parameter.getEnclosingMethod() != currentMethod) {
1751          throw new InternalCompilerException(
1752              "ParameterRef referencing param in a different method.");
1753        }
1754        return new JParameterRef(program, info, parameter);
1755      } else if (variable instanceof JField) {
1756        JField field = (JField) variable;
1757        JExpression instance = null;
1758        if (!field.isStatic()) {
1759          JClassType fieldEnclosingType = (JClassType) field.getEnclosingType();
1760          instance = createThisRef(info, fieldEnclosingType);
1761          if (!program.typeOracle.canTriviallyCast(
1762              (JClassType) instance.getType(), fieldEnclosingType)) {
1763            throw new InternalCompilerException(
1764                "FieldRef referencing field in a different type.");
1765          }
1766        }
1767        return new JFieldRef(program, info, instance, field, currentClass);
1768      }
1769      throw new InternalCompilerException("Unknown JVariable subclass.");
1770    }
1771
1772    /**
1773     * Creates an appropriate JVariableRef for the polymorphic type of the
1774     * requested JVariable.
1775     */

1776    private JVariableRef createVariableRef(SourceInfo info, JVariable variable,
1777        Binding binding) {
1778      // Fix up the reference if it's to an outer local/param
1779
variable = possiblyReferenceOuterLocal(variable, binding);
1780      if (variable == null) {
1781        /*
1782         * Strange case: in certain circumstances, JDT will fail to provide an
1783         * emulation path to an outer local variable. In the case I know of, the
1784         * reference is a spurious qualifier to a static method call. Let's just
1785         * return null and ditch the expression.
1786         */

1787        return null;
1788      }
1789      return createVariableRef(info, variable);
1790    }
1791
1792    /**
1793     * Get a new label of a particular name, or create a new one if it doesn't
1794     * exist already.
1795     */

1796    private JLabel getOrCreateLabel(SourceInfo info, JMethod enclosingMethod,
1797        char[] name) {
1798      if (name == null) {
1799        return null;
1800      }
1801      String JavaDoc sname = String.valueOf(name);
1802      Map JavaDoc/* <String, JLabel> */lblMap = (Map JavaDoc) this.labelMap.get(enclosingMethod);
1803      if (lblMap == null) {
1804        lblMap = new HashMap JavaDoc();
1805        this.labelMap.put(enclosingMethod, lblMap);
1806      }
1807      JLabel jlabel = (JLabel) lblMap.get(sname);
1808      if (jlabel == null) {
1809        jlabel = new JLabel(program, info, sname);
1810        lblMap.put(sname, jlabel);
1811      }
1812      return jlabel;
1813    }
1814
1815    private SourceInfo makeSourceInfo(Statement x) {
1816      int startLine = ProblemHandler.searchLineNumber(
1817          currentSeparatorPositions, x.sourceStart);
1818      return new SourceInfo(x.sourceStart, x.sourceEnd, startLine,
1819          currentFileName);
1820    }
1821
1822    private HasEnclosingType parseJsniRef(SourceInfo info,
1823        AbstractMethodDeclaration x, String JavaDoc ident) {
1824      String JavaDoc[] parts = ident.substring(1).split("::");
1825      assert (parts.length == 2);
1826      String JavaDoc className = parts[0];
1827      JReferenceType type = program.getFromTypeMap(className);
1828      if (type == null) {
1829        reportJsniError(info, x, "Unresolvable native reference to type '"
1830            + className + "'");
1831        return null;
1832      }
1833      String JavaDoc rhs = parts[1];
1834      int parenPos = rhs.indexOf('(');
1835      if (parenPos < 0) {
1836        // look for a field
1837
for (int i = 0; i < type.fields.size(); ++i) {
1838          JField field = (JField) type.fields.get(i);
1839          if (field.getName().equals(rhs)) {
1840            return field;
1841          }
1842        }
1843
1844        reportJsniError(info, x, "Unresolvable native reference to field '"
1845            + rhs + "' in type '" + className + "'");
1846      } else {
1847        // look for a method
1848
String JavaDoc methodName = rhs.substring(0, parenPos);
1849        String JavaDoc almostMatches = null;
1850        for (int i = 0; i < type.methods.size(); ++i) {
1851          JMethod method = (JMethod) type.methods.get(i);
1852          if (method.getName().equals(methodName)) {
1853            String JavaDoc jsniSig = getJsniSig(method);
1854            if (jsniSig.equals(rhs)) {
1855              return method;
1856            } else if (almostMatches == null) {
1857              almostMatches = "'" + jsniSig + "'";
1858            } else {
1859              almostMatches += ", '" + jsniSig + "'";
1860            }
1861          }
1862        }
1863
1864        if (almostMatches == null) {
1865          reportJsniError(info, x, "Unresolvable native reference to method '"
1866              + methodName + "' in type '" + className + "'");
1867        } else {
1868          reportJsniError(info, x, "Unresolvable native reference to method '"
1869              + methodName + "' in type '" + className + "' (did you mean "
1870              + almostMatches + "?)");
1871        }
1872      }
1873      return null;
1874    }
1875
1876    /**
1877     * Sometimes a variable reference can be to a local or parameter in an an
1878     * enclosing method. This is a tricky situation to detect. There's no
1879     * obvious way to tell, but the clue we can get from JDT is that the local's
1880     * containing method won't be the same as the method we're currently
1881     * processing.
1882     *
1883     * Once we have this clue, we can use getEmulationPath to compute the
1884     * current class's binding for that field.
1885     */

1886    private JVariable possiblyReferenceOuterLocal(JVariable variable,
1887        Binding binding) {
1888
1889      if (variable instanceof JLocal || variable instanceof JParameter) {
1890        LocalVariableBinding localBinding = (LocalVariableBinding) binding;
1891        if (localBinding.declaringScope.methodScope() != currentMethodScope) {
1892          variable = null;
1893          VariableBinding[] vars = currentMethodScope.getEmulationPath(localBinding);
1894          if (vars == null) {
1895            return null;
1896          }
1897          assert (vars.length == 1);
1898          VariableBinding varBinding = vars[0];
1899
1900          // See if there's an available parameter
1901
if (varBinding instanceof SyntheticArgumentBinding) {
1902            JType type = (JType) typeMap.get(varBinding.type);
1903            String JavaDoc name = String.valueOf(varBinding.name);
1904            for (int i = 0; i < currentMethod.params.size(); ++i) {
1905              JParameter param = (JParameter) currentMethod.params.get(i);
1906              if (type == param.getType() && name.equals(param.getName())) {
1907                variable = param;
1908                break;
1909              }
1910            }
1911          }
1912
1913          // just use the field
1914
if (variable == null) {
1915            variable = (JField) typeMap.get(varBinding);
1916          }
1917
1918          // now we have an updated variable that we can create our ref from
1919
}
1920      }
1921      return variable;
1922    }
1923
1924    /**
1925     * Helper for creating all JBinaryOperation. Several different JDT nodes can
1926     * result in binary operations: AND_AND_Expression, Assignment,
1927     * BinaryExpresion, CompoundAssignment, EqualExpression, and
1928     * OR_OR_Expression. Hopefully the specific operators that can result in
1929     * each different JDT type won't change between releases, because we only
1930     * look for the specific operators that we think should match each JDT node,
1931     * and throw an error if there's a mismatch.
1932     */

1933    private JExpression processBinaryOperation(SourceInfo info,
1934        JBinaryOperator op, JType type, Expression arg1, Expression arg2) {
1935      JExpression exprArg1 = dispProcessExpression(arg1);
1936      JExpression exprArg2 = dispProcessExpression(arg2);
1937      JBinaryOperation binaryOperation = new JBinaryOperation(program, info,
1938          type, op, exprArg1, exprArg2);
1939      return binaryOperation;
1940    }
1941
1942    private JExpression processQualifiedThisOrSuperRef(
1943        QualifiedThisReference x, JClassType qualType) {
1944      /*
1945       * WEIRD: If a thisref or superref is qualified with the EXACT type of the
1946       * innermost type (in other words, a needless qualifier), it must refer to
1947       * that innermost type, because a class can never be nested inside of
1948       * itself. In this case, we must treat it as if it were not qualified.
1949       *
1950       * In all other cases, the qualified thisref or superref cannot possibly
1951       * refer to the innermost type (even if the innermost type could be cast
1952       * to a compatible type), so we must create a reference to some outer
1953       * type.
1954       */

1955      SourceInfo info = makeSourceInfo(x);
1956      if (qualType == currentClass) {
1957        return createThisRef(info, qualType);
1958      } else {
1959        return createQualifiedThisRef(info, qualType);
1960      }
1961    }
1962
1963    private InternalCompilerException translateException(Object JavaDoc node,
1964        Throwable JavaDoc e) {
1965      InternalCompilerException ice;
1966      if (e instanceof InternalCompilerException) {
1967        ice = (InternalCompilerException) e;
1968      } else {
1969        ice = new InternalCompilerException("Error constructing Java AST", e);
1970      }
1971      String JavaDoc className = node.getClass().getName();
1972      String JavaDoc description = node.toString();
1973      SourceInfo sourceInfo = null;
1974      if (node instanceof Statement) {
1975        sourceInfo = makeSourceInfo((Statement) node);
1976      }
1977      ice.addNode(className, description, sourceInfo);
1978      return ice;
1979    }
1980
1981    /**
1982     * For a given method(and method binding), try to find all methods that it
1983     * overrides/implements.
1984     */

1985    private void tryFindUpRefs(JMethod method, MethodBinding binding) {
1986      tryFindUpRefsRecursive(method, binding, binding.declaringClass);
1987    }
1988
1989    /**
1990     * For a given method(and method binding), recursively try to find all
1991     * methods that it overrides/implements.
1992     */

1993    private void tryFindUpRefsRecursive(JMethod method, MethodBinding binding,
1994        ReferenceBinding searchThisType) {
1995
1996      // See if this class has any uprefs, unless this class is myself
1997
if (binding.declaringClass != searchThisType) {
1998        MethodBinding result = searchThisType.getExactMethod(binding.selector,
1999            binding.parameters, null);
2000
2001        if (result != null) {
2002          if (areParametersIdentical(binding, result)) {
2003            JMethod upRef = (JMethod) typeMap.get(result);
2004            if (!method.overrides.contains(upRef)) {
2005              method.overrides.add(upRef);
2006            }
2007          }
2008        }
2009      }
2010
2011      // recurse super class
2012
if (searchThisType.superclass() != null) {
2013        tryFindUpRefsRecursive(method, binding, searchThisType.superclass());
2014      }
2015
2016      // recurse super interfaces
2017
if (searchThisType.superInterfaces() != null) {
2018        for (int i = 0; i < searchThisType.superInterfaces().length; i++) {
2019          ReferenceBinding intf = searchThisType.superInterfaces()[i];
2020          tryFindUpRefsRecursive(method, binding, intf);
2021        }
2022      }
2023    }
2024  }
2025
2026  /**
2027   * Combines the information from the JDT type nodes and the type map to create
2028   * a JProgram structure.
2029   */

2030  public static void exec(TypeDeclaration[] types, TypeMap typeMap,
2031      JProgram jprogram) {
2032    JavaASTGenerationVisitor v = new JavaASTGenerationVisitor(typeMap);
2033    for (int i = 0; i < types.length; ++i) {
2034      v.processType(types[i]);
2035    }
2036    Collections.sort(jprogram.getDeclaredTypes(), new HasNameSort());
2037  }
2038
2039  public static void reportJsniError(SourceInfo info,
2040      AbstractMethodDeclaration methodDeclaration, String JavaDoc message) {
2041    CompilationResult compResult = methodDeclaration.compilationResult();
2042    DefaultProblem problem = new DefaultProblem(
2043        info.getFileName().toCharArray(), message, IProblem.Unclassified, null,
2044        ProblemSeverities.Error, info.getStartPos(), info.getEndPos(),
2045        info.getStartLine());
2046    compResult.record(problem, methodDeclaration);
2047  }
2048
2049  public static SourceInfo translateInfo(JsSourceInfo info) {
2050    // TODO implement this
2051
return null;
2052  }
2053
2054  /**
2055   * Gets a JParameter iterator for a constructor method over its synthetic
2056   * parameters.
2057   */

2058  private static Iterator JavaDoc getSyntheticsIterator(JMethod method) {
2059    Iterator JavaDoc it = method.params.iterator();
2060    for (int i = 0, c = method.getOriginalParamTypes().size(); i < c; ++i) {
2061      it.next();
2062    }
2063    return it;
2064  }
2065
2066  /**
2067   * Returns <code>true</code> if JDT optimized the condition to
2068   * <code>false</code>.
2069   */

2070  private static boolean isOptimizedFalse(Expression condition) {
2071    if (condition != null) {
2072      Constant cst = condition.optimizedBooleanConstant();
2073      if (cst != Constant.NotAConstant) {
2074        if (cst.booleanValue() == false) {
2075          return true;
2076        }
2077      }
2078    }
2079    return false;
2080  }
2081
2082  /**
2083   * Returns <code>true</code> if JDT optimized the condition to
2084   * <code>true</code>.
2085   */

2086  private static boolean isOptimizedTrue(Expression condition) {
2087    if (condition != null) {
2088      Constant cst = condition.optimizedBooleanConstant();
2089      if (cst != Constant.NotAConstant) {
2090        if (cst.booleanValue() == true) {
2091          return true;
2092        }
2093      }
2094    }
2095    return false;
2096  }
2097
2098}
2099
Popular Tags