added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / Statement.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.ast;
12
13 import org.eclipse.jdt.internal.compiler.codegen.*;
14 import org.eclipse.jdt.internal.compiler.flow.*;
15 import org.eclipse.jdt.internal.compiler.impl.Constant;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17
18 public abstract class Statement extends ASTNode {
19         
20         public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo);
21         
22         /**
23          * INTERNAL USE ONLY.
24          * This is used to redirect inter-statements jumps.
25          */
26         public void branchChainTo(Label label) {
27                 // do nothing by default
28         }
29         
30         // Report an error if necessary
31         public boolean complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) {
32         
33                 if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
34                         this.bits &= ~ASTNode.IsReachableMASK;
35                         boolean reported = flowInfo == FlowInfo.DEAD_END;
36                         if (!didAlreadyComplain && reported) {
37                                 scope.problemReporter().unreachableCode(this);
38                         }
39                         return reported; // keep going for fake reachable
40                 }
41                 return false;
42         }
43
44         /**
45          * Generate invocation arguments, considering varargs methods
46          */
47         public void generateArguments(MethodBinding binding, Expression[] arguments, BlockScope currentScope, CodeStream codeStream) {
48                 
49                 if (binding.isVarargs()) {
50                         // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) : 
51                         //      foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2})
52                         TypeBinding[] params = binding.parameters;
53                         int paramLength = params.length;
54                         int varArgIndex = paramLength - 1;
55                         for (int i = 0; i < varArgIndex; i++) {
56                                 arguments[i].generateCode(currentScope, codeStream, true);
57                         }
58
59                         ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type
60                         int argLength = arguments == null ? 0 : arguments.length;
61
62                         generateVarargsArgument: {
63                                 if (argLength >= paramLength) {
64                                         // right number of arguments - could be inexact - pass argument as is
65                                         TypeBinding lastType = arguments[varArgIndex].resolvedType;
66                                         if (lastType == NullBinding || varArgsType.dimensions() == lastType.dimensions()) {
67                                                 // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is
68                                                 arguments[varArgIndex].generateCode(currentScope, codeStream, true);
69                                                 break generateVarargsArgument;
70                                         }
71                                         // right number but not directly compatible or too many arguments - wrap extra into array
72                                         // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4)
73                                         // need to gen elements into an array, then gen each remaining element into created array
74                                         codeStream.generateInlinedValue(argLength - varArgIndex);
75                                         codeStream.newArray(varArgsType); // create a mono-dimensional array
76                                         int elementsTypeID = varArgsType.elementsType().id;
77                                         for (int i = varArgIndex; i < argLength; i++) {
78                                                 codeStream.dup();
79                                                 codeStream.generateInlinedValue(i - varArgIndex);
80                                                 arguments[i].generateCode(currentScope, codeStream, true);
81                                                 codeStream.arrayAtPut(elementsTypeID, false);
82                                         }
83                                 } else { // not enough arguments - pass extra empty array
84                                         // scenario: foo(1) --> foo(1, new int[0])
85                                         // generate code for an empty array of parameterType
86                                         codeStream.generateInlinedValue(0);
87                                         codeStream.newArray(varArgsType); // create a mono-dimensional array
88                                 }
89                         }
90                 } else if (arguments != null) { // standard generation for method arguments
91                         for (int i = 0, max = arguments.length; i < max; i++)
92                                 arguments[i].generateCode(currentScope, codeStream, true);
93                 }
94         }
95
96         public abstract void generateCode(BlockScope currentScope, CodeStream codeStream);
97         
98         public boolean isEmptyBlock() {
99                 return false;
100         }
101         
102         public boolean isValidJavaStatement() {
103                 //the use of this method should be avoid in most cases
104                 //and is here mostly for documentation purpose.....
105                 //while the parser is responsable for creating
106                 //welled formed expression statement, which results
107                 //in the fact that java-non-semantic-expression-used-as-statement
108                 //should not be parsable...thus not being built.
109                 //It sounds like the java grammar as help the compiler job in removing
110                 //-by construction- some statement that would have no effect....
111                 //(for example all expression that may do side-effects are valid statement
112                 // -this is an appromative idea.....-)
113
114                 return true;
115         }
116         
117         public StringBuffer print(int indent, StringBuffer output) {
118                 return printStatement(indent, output);
119         }
120         public abstract StringBuffer printStatement(int indent, StringBuffer output);
121
122         public abstract void resolve(BlockScope scope);
123         
124         /**
125          * Returns case constant associated to this statement (NotAConstant if none)
126          */
127         public Constant resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) {
128                 // statement within a switch that are not case are treated as normal statement.... 
129
130                 resolve(scope);
131                 return NotAConstant;
132         }
133
134 }