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