### Eclipse Workspace Patch 1.0
#P org.eclipse.jdt.core
Index: compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java,v
retrieving revision 1.59
diff -u -r1.59 BinaryExpression.java
--- compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 28 Mar 2006 20:29:56 -0000 1.59
+++ compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 26 Jun 2006 10:14:11 -0000
@@ -18,6 +18,19 @@
import org.eclipse.jdt.internal.compiler.lookup.*;
public class BinaryExpression extends OperatorExpression {
+
+/* Tracking helpers
+ * The following are used to elaborate realistic statistics about binary
+ * expressions. This must be neutralized in the released code.
+ * Search the keyword BE_INSTRUMENTATION to reenable.
+ * An external device must install a suitable probe so as to monitor the
+ * emission of events and publish the results.
+ public interface Probe {
+ public void ping(int depth);
+ }
+ public int depthTracker;
+ public static Probe probe;
+ */
public Expression left, right;
public Constant optimizedBooleanConstant;
@@ -28,9 +41,18 @@
this.bits |= operator << ASTNode.OperatorSHIFT; // encode operator
this.sourceStart = left.sourceStart;
this.sourceEnd = right.sourceEnd;
+ // BE_INSTRUMENTATION: neutralized in the released code
+// if (left instanceof BinaryExpression &&
+// ((left.bits & OperatorMASK) ^ (this.bits & OperatorMASK)) == 0) {
+// this.depthTracker = ((BinaryExpression)left).depthTracker + 1;
+// } else {
+// this.depthTracker = 1;
+// }
}
-public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
+public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
+ FlowInfo flowInfo) {
+ // keep implementation in sync with CombinedBinaryExpression#analyseCode
if (this.resolvedType.id == TypeIds.T_JavaLangString) {
return this.right.analyseCode(
currentScope, flowContext,
@@ -78,6 +100,9 @@
/**
* Code generation for a binary operation
*/
+// given the current focus of CombinedBinaryExpression on strings concatenation,
+// we do not provide a general, non-recursive implementation of generateCode,
+// but rely upon generateOptimizedStringConcatenationCreation instead
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
int pc = codeStream.position;
if (this.constant != Constant.NotAConstant) {
@@ -90,6 +115,10 @@
case PLUS :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_JavaLangString :
+ // BE_INSTRUMENTATION: neutralized in the released code
+// if (probe != null) {
+// probe.ping(this.depthTracker);
+// }
codeStream.generateStringConcatenationAppend(currentScope, this.left, this.right);
if (!valueRequired)
codeStream.pop();
@@ -1511,7 +1540,8 @@
}
public void generateOptimizedStringConcatenation(BlockScope blockScope, CodeStream codeStream, int typeID) {
-
+ // keep implementation in sync with CombinedBinaryExpression
+ // #generateOptimizedStringConcatenation
/* In the case trying to make a string concatenation, there is no need to create a new
* string buffer, thus use a lower-level API for code generation involving only the
* appending of arguments to the existing StringBuffer
@@ -1542,12 +1572,12 @@
}
public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, CodeStream codeStream, int typeID) {
-
+ // keep implementation in sync with CombinedBinaryExpression
+ // #generateOptimizedStringConcatenationCreation
/* In the case trying to make a string concatenation, there is no need to create a new
* string buffer, thus use a lower-level API for code generation involving only the
* appending of arguments to the existing StringBuffer
*/
-
if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS)
&& ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) {
if (this.constant != Constant.NotAConstant) {
@@ -1579,6 +1609,123 @@
return true;
}
+/**
+ * Separates into a reusable method the subpart of {@link
+ * #resolveType(BlockScope)} that needs to be executed while climbing up the
+ * chain of expressions of this' leftmost branch. For use by {@link
+ * CombinedBinaryExpression#resolveType(BlockScope)}.
+ * @param scope the scope within which the resolution occurs
+ */
+void nonRecursiveResolveTypeUpwards(BlockScope scope) {
+ // keep implementation in sync with BinaryExpression#resolveType
+ boolean leftIsCast, rightIsCast;
+ TypeBinding leftType = this.left.resolvedType;
+
+ if ((rightIsCast = this.right instanceof CastExpression) == true) {
+ this.right.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
+ }
+ TypeBinding rightType = this.right.resolveType(scope);
+
+ // use the id of the type to navigate into the table
+ if (leftType == null || rightType == null) {
+ this.constant = Constant.NotAConstant;
+ return;
+ }
+
+ int leftTypeID = leftType.id;
+ int rightTypeID = rightType.id;
+
+ // autoboxing support
+ boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
+ if (use15specifics) {
+ if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) {
+ leftTypeID = scope.environment().computeBoxingType(leftType).id;
+ }
+ if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) {
+ rightTypeID = scope.environment().computeBoxingType(rightType).id;
+ }
+ }
+ if (leftTypeID > 15
+ || rightTypeID > 15) { // must convert String + Object || Object + String
+ if (leftTypeID == TypeIds.T_JavaLangString) {
+ rightTypeID = TypeIds.T_JavaLangObject;
+ } else if (rightTypeID == TypeIds.T_JavaLangString) {
+ leftTypeID = TypeIds.T_JavaLangObject;
+ } else {
+ this.constant = Constant.NotAConstant;
+ scope.problemReporter().invalidOperator(this, leftType, rightType);
+ return;
+ }
+ }
+ if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) {
+ if (leftTypeID == TypeIds.T_JavaLangString) {
+ this.left.computeConversion(scope, leftType, leftType);
+ if (rightType.isArrayType() && ((ArrayBinding) rightType).elementsType() == TypeBinding.CHAR) {
+ scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right);
+ }
+ }
+ if (rightTypeID == TypeIds.T_JavaLangString) {
+ this.right.computeConversion(scope, rightType, rightType);
+ if (leftType.isArrayType() && ((ArrayBinding) leftType).elementsType() == TypeBinding.CHAR) {
+ scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left);
+ }
+ }
+ }
+
+ // the code is an int
+ // (cast) left Op (cast) right --> result
+ // 0000 0000 0000 0000 0000
+ // <<16 <<12 <<8 <<4 <<0
+
+ // Don't test for result = 0. If it is zero, some more work is done.
+ // On the one hand when it is not zero (correct code) we avoid doing the test
+ int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
+ int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID];
+
+ this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType);
+ this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType);
+ this.bits |= operatorSignature & 0xF;
+ switch (operatorSignature & 0xF) { // record the current ReturnTypeID
+ // only switch on possible result type.....
+ case T_boolean :
+ this.resolvedType = TypeBinding.BOOLEAN;
+ break;
+ case T_byte :
+ this.resolvedType = TypeBinding.BYTE;
+ break;
+ case T_char :
+ this.resolvedType = TypeBinding.CHAR;
+ break;
+ case T_double :
+ this.resolvedType = TypeBinding.DOUBLE;
+ break;
+ case T_float :
+ this.resolvedType = TypeBinding.FLOAT;
+ break;
+ case T_int :
+ this.resolvedType = TypeBinding.INT;
+ break;
+ case T_long :
+ this.resolvedType = TypeBinding.LONG;
+ break;
+ case T_JavaLangString :
+ this.resolvedType = scope.getJavaLangString();
+ break;
+ default : //error........
+ this.constant = Constant.NotAConstant;
+ scope.problemReporter().invalidOperator(this, leftType, rightType);
+ return;
+ }
+
+ // check need for operand cast
+ if ((leftIsCast = (this.left instanceof CastExpression)) == true ||
+ rightIsCast) {
+ CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast);
+ }
+ // compute the constant when valid
+ computeConstant(scope, leftTypeID, rightTypeID);
+}
+
public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
switch (operator) {
case AND :
@@ -1628,11 +1775,15 @@
}
public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
+ // keep implementation in sync with
+ // CombinedBinaryExpression#printExpressionNoParenthesis
this.left.printExpression(indent, output).append(' ').append(operatorToString()).append(' ');
return this.right.printExpression(0, output);
}
-
+
public TypeBinding resolveType(BlockScope scope) {
+ // keep implementation in sync with CombinedBinaryExpression#resolveType
+ // and nonRecursiveResolveTypeUpwards
boolean leftIsCast, rightIsCast;
if ((leftIsCast = this.left instanceof CastExpression) == true) this.left.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
TypeBinding leftType = this.left.resolveType(scope);
Index: compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java,v
retrieving revision 1.347
diff -u -r1.347 Parser.java
--- compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java 21 Jun 2006 14:39:35 -0000 1.347
+++ compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java 26 Jun 2006 10:14:15 -0000
@@ -1528,8 +1528,39 @@
} else {
this.expressionStack[this.expressionPtr] = new BinaryExpression(expr1, expr2, PLUS);
}
+ } else if (expr1 instanceof CombinedBinaryExpression) {
+ CombinedBinaryExpression cursor;
+ // left branch is comprised of PLUS BEs
+ // cursor is shifted upwards, while needed BEs are added
+ // on demand; past the arityMax-th
+ // consecutive BE, a CBE is inserted that holds a
+ // full-fledged references table
+ if ((cursor = (CombinedBinaryExpression)expr1).arity <
+ cursor.arityMax) {
+ cursor.left = new BinaryExpression(cursor.left,
+ cursor.right, PLUS);
+ cursor.arity++;
+ } else {
+ cursor.left = new CombinedBinaryExpression(cursor.left,
+ cursor.right, PLUS, cursor.arity);
+ cursor.arity = 0;
+ cursor.tuneArityMax();
+ }
+ cursor.right = expr2;
+ cursor.sourceEnd = expr2.sourceEnd;
+ this.expressionStack[this.expressionPtr] = cursor;
+ // BE_INSTRUMENTATION: neutralized in the released code
+// cursor.depthTracker = ((BinaryExpression)cursor.left).
+// depthTracker + 1;
+ } else if (expr1 instanceof BinaryExpression) {
+ this.expressionStack[this.expressionPtr] =
+ new CombinedBinaryExpression(expr1, expr2, PLUS, 1);
} else {
- this.expressionStack[this.expressionPtr] = new BinaryExpression(expr1, expr2, PLUS);
+ // single out the a + b case, which is a BE
+ // instead of a CBE (slightly more than a half of strings
+ // concatenation are one-deep binary expressions)
+ this.expressionStack[this.expressionPtr] =
+ new BinaryExpression(expr1, expr2, PLUS);
}
} else if (expr1 instanceof StringLiteral) {
if (expr2 instanceof StringLiteral) {
@@ -1537,19 +1568,38 @@
this.expressionStack[this.expressionPtr] =
((StringLiteral) expr1).extendsWith((StringLiteral) expr2);
} else {
+ // single out the a + b case
this.expressionStack[this.expressionPtr] =
- new BinaryExpression(
- expr1,
- expr2,
- op);
+ new BinaryExpression(expr1, expr2, PLUS);
+ }
+ } else if (expr1 instanceof CombinedBinaryExpression) {
+ CombinedBinaryExpression cursor;
+ // shift cursor; create BE/CBE as needed
+ if ((cursor = (CombinedBinaryExpression)expr1).arity <
+ cursor.arityMax) {
+ cursor.left = new BinaryExpression(cursor.left,
+ cursor.right, PLUS);
+ cursor.arity++;
+ } else {
+ cursor.left = new CombinedBinaryExpression(cursor.left,
+ cursor.right, PLUS, cursor.arity);
+ cursor.arity = 0;
+ cursor.tuneArityMax();
+ }
+ cursor.right = expr2;
+ cursor.sourceEnd = expr2.sourceEnd;
+ // BE_INSTRUMENTATION: neutralized in the released code
+// cursor.depthTracker = ((BinaryExpression)cursor.left).
+// depthTracker + 1;
+ this.expressionStack[this.expressionPtr] = cursor;
+ } else if (expr1 instanceof BinaryExpression) {
+ this.expressionStack[this.expressionPtr] =
+ new CombinedBinaryExpression(expr1, expr2, PLUS, 1);
+ } else {
+ // single out the a + b case
+ this.expressionStack[this.expressionPtr] =
+ new BinaryExpression(expr1, expr2, PLUS);
}
- } else {
- this.expressionStack[this.expressionPtr] =
- new BinaryExpression(
- expr1,
- expr2,
- op);
- }
break;
case LESS :
this.intPtr--;
@@ -1619,6 +1669,8 @@
*/
Expression expr1 = this.expressionStack[this.expressionPtr + 1];
Expression expr2 = this.expressionStack[this.expressionPtr];
+ // Note: we do not attempt to promote BinaryExpression-s to
+ // IndexedBinaryExpression-s here since expr1 always holds a name
switch(op) {
case OR_OR :
this.expressionStack[this.expressionPtr] =
Index: compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java
===================================================================
RCS file: compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java
diff -N compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,393 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
+import org.eclipse.jdt.internal.compiler.flow.FlowContext;
+import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/**
+ * CombinedBinaryExpression is an implementation of BinaryExpression that
+ * specifically attempts to mitigate the issues raised by expressions which
+ * have a very deep leftmost branch. It does so by maintaining a table of
+ * direct references to its subexpressions, and implementing non-recursive
+ * variants of the most significant recursive algorithms of its ancestors.
+ * The subexpressions table only holds intermediate binary expressions. Its
+ * role is to provide the reversed navigation through the left relationship
+ * of BinaryExpression to Expression. To cope with potentially very deep
+ * left branches, an instance of CombinedBinaryExpression is created once in
+ * a while, using variable thresholds held by {@link #arityMax}.
+ * As a specific case, the topmost node of all binary expressions that are
+ * deeper than one is a CombinedBinaryExpression, but it has no references
+ * table.
+ * Notes:
+ *
+ * - CombinedBinaryExpression is not meant to behave in other ways than
+ * BinaryExpression in any observable respect;
+ * - visitors that implement their own traversal upon binary expressions
+ * should consider taking advantage of combined binary expressions, or
+ * else face a risk of StackOverflowError upon deep instances;
+ * - callers that need to change the operator should rebuild the expression
+ * from scratch, or else amend the references table as needed to cope with
+ * the resulting, separated expressions.
+ *
+ */
+public class CombinedBinaryExpression extends BinaryExpression {
+
+ /**
+ * The number of consecutive binary expressions of this' left branch that
+ * bear the same operator as this.
+ * Notes:
+ * - the presence of a CombinedBinaryExpression instance resets
+ * arity, even when its operator is compatible;
+ * - this property is maintained by the parser.
+ *
+ */
+ public int arity;
+
+ /**
+ * The threshold that will trigger the creation of the next full-fledged
+ * CombinedBinaryExpression. This field is only maintained for the
+ * topmost binary expression (it is 0 otherwise). It enables a variable
+ * policy, which scales better with very large expressions.
+ */
+ public int arityMax;
+
+ /**
+ * Upper limit for {@link #arityMax}.
+ */
+ public static final int ARITY_MAX_MAX = 160;
+
+ /**
+ * Default lower limit for {@link #arityMax}.
+ */
+ public static final int ARITY_MAX_MIN = 20;
+
+ /**
+ * Default value for the first term of the series of {@link #arityMax}
+ * values. Changing this allows for experimentation. Not meant to be
+ * changed during a parse operation.
+ */
+ public static int defaultArityMaxStartingValue = ARITY_MAX_MIN;
+
+ /**
+ * A table of references to the binary expressions of this' left branch.
+ * Instances of CombinedBinaryExpression are not repeated here. Instead,
+ * the left subexpression of referencesTable[0] may be a combined binary
+ * expression, if appropriate. Null when this only cares about tracking
+ * the expression's arity.
+ */
+ public BinaryExpression referencesTable[];
+
+/**
+ * Make a new CombinedBinaryExpression. If arity is strictly greater than one,
+ * a references table is built and initialized with the reverse relationship of
+ * the one defined by {@link BinaryExpression#left}. arity and left must be
+ * compatible with each other (that is, there must be at least arity - 1
+ * consecutive compatible binary expressions into the leftmost branch of left,
+ * the topmost of which being left's immediate left expression).
+ * @param left the left branch expression
+ * @param right the right branch expression
+ * @param operator the operator for this binary expression - only PLUS for now
+ * @param arity the number of binary expressions of a compatible operator that
+ * already exist into the leftmost branch of left (including left); must
+ * be strictly greater than 0
+ */
+public CombinedBinaryExpression(Expression left, Expression right, int operator,
+ int arity) {
+ super(left, right, operator);
+ this.arity = arity;
+ if (arity > 1) {
+ this.referencesTable = new BinaryExpression[arity];
+ this.referencesTable[arity - 1] = (BinaryExpression) left;
+ for (int i = arity - 1; i > 0; i--) {
+ this.referencesTable[i - 1] =
+ (BinaryExpression) this.referencesTable[i].left;
+ }
+ } else {
+ this.arityMax = defaultArityMaxStartingValue;
+ }
+}
+
+public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
+ FlowInfo flowInfo) {
+ // keep implementation in sync with BinaryExpression#analyseCode
+ if (this.referencesTable == null) {
+ return super.analyseCode(currentScope, flowContext, flowInfo);
+ }
+ BinaryExpression cursor;
+ if ((cursor = this.referencesTable[0]).resolvedType.id !=
+ TypeIds.T_JavaLangString) {
+ cursor.left.checkNPE(currentScope, flowContext, flowInfo);
+ }
+ flowInfo = cursor.left.analyseCode(currentScope, flowContext, flowInfo).
+ unconditionalInits();
+ for (int i = 0, end = this.arity; i < end; i ++) {
+ if ((cursor = this.referencesTable[i]).resolvedType.id !=
+ TypeIds.T_JavaLangString) {
+ cursor.right.checkNPE(currentScope, flowContext, flowInfo);
+ }
+ flowInfo = cursor.right.
+ analyseCode(currentScope, flowContext, flowInfo).
+ unconditionalInits();
+ }
+ if (this.resolvedType.id != TypeIds.T_JavaLangString) {
+ this.right.checkNPE(currentScope, flowContext, flowInfo);
+ }
+ return this.right.analyseCode(currentScope, flowContext, flowInfo).
+ unconditionalInits();
+}
+
+public void generateOptimizedStringConcatenation(BlockScope blockScope,
+ CodeStream codeStream, int typeID) {
+ // keep implementation in sync with BinaryExpression and Expression
+ // #generateOptimizedStringConcatenation
+ if (this.referencesTable == null) {
+ super.generateOptimizedStringConcatenation(blockScope, codeStream,
+ typeID);
+ } else {
+ if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) ==
+ OperatorIds.PLUS)
+ && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) {
+ if (this.constant != Constant.NotAConstant) {
+ codeStream.generateConstant(this.constant, this.implicitConversion);
+ codeStream.invokeStringConcatenationAppendForType(
+ this.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
+ } else {
+ BinaryExpression cursor = this.referencesTable[0];
+
+ int restart = 0;
+ // int cursorTypeID;
+ int pc = codeStream.position;
+ for (restart = this.arity - 1; restart >= 0; restart--) {
+ if ((cursor = this.referencesTable[restart]).constant !=
+ Constant.NotAConstant) {
+ codeStream.generateConstant(cursor.constant,
+ cursor.implicitConversion);
+ codeStream.invokeStringConcatenationAppendForType(
+ cursor.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
+ break;
+ }
+ // never happens for now - may reconsider if we decide to
+ // cover more than string concatenation
+ // if (!((((cursor = this.referencesTable[restart]).bits &
+ // ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) ==
+ // OperatorIds.PLUS) &
+ // ((cursorTypeID = cursor.bits & ASTNode.ReturnTypeIDMASK) ==
+ // TypeIds.T_JavaLangString)) {
+ // if (cursorTypeID == T_JavaLangString &&
+ // cursor.constant != Constant.NotAConstant &&
+ // cursor.constant.stringValue().length() == 0) {
+ // break; // optimize str + ""
+ // }
+ // cursor.generateCode(blockScope, codeStream, true);
+ // codeStream.invokeStringConcatenationAppendForType(
+ // cursorTypeID);
+ // break;
+ // }
+ }
+ restart++;
+ if (restart == 0) { // reached the leftmost expression
+ cursor.left.generateOptimizedStringConcatenation(
+ blockScope,
+ codeStream,
+ cursor.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
+ }
+ int pcAux;
+ for (int i = restart; i < this.arity; i++) {
+ codeStream.recordPositionsFrom(pc,
+ (cursor = this.referencesTable[i]).left.sourceStart);
+ pcAux = codeStream.position;
+ cursor.right.generateOptimizedStringConcatenation(blockScope,
+ codeStream, cursor.right.implicitConversion &
+ TypeIds.COMPILE_TYPE_MASK);
+ codeStream.recordPositionsFrom(pcAux, cursor.right.sourceStart);
+ }
+ codeStream.recordPositionsFrom(pc, this.left.sourceStart);
+ pc = codeStream.position;
+ this.right.generateOptimizedStringConcatenation(
+ blockScope,
+ codeStream,
+ this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
+ codeStream.recordPositionsFrom(pc, this.right.sourceStart);
+ }
+ } else {
+ super.generateOptimizedStringConcatenation(blockScope, codeStream,
+ typeID);
+ }
+ }
+}
+
+public void generateOptimizedStringConcatenationCreation(BlockScope blockScope,
+ CodeStream codeStream, int typeID) {
+ // keep implementation in sync with BinaryExpression
+ // #generateOptimizedStringConcatenationCreation
+ if (this.referencesTable == null) {
+ super.generateOptimizedStringConcatenationCreation(blockScope,
+ codeStream, typeID);
+ } else {
+ if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) ==
+ OperatorIds.PLUS) &&
+ ((this.bits & ASTNode.ReturnTypeIDMASK) ==
+ TypeIds.T_JavaLangString) &&
+ this.constant == Constant.NotAConstant) {
+ int pc = codeStream.position;
+ BinaryExpression cursor = this.referencesTable[this.arity - 1];
+ // silence warnings
+ int restart = 0;
+ for (restart = this.arity - 1; restart >= 0; restart--) {
+ if (((((cursor = this.referencesTable[restart]).bits &
+ ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) ==
+ OperatorIds.PLUS) &&
+ ((cursor.bits & ASTNode.ReturnTypeIDMASK) ==
+ TypeIds.T_JavaLangString)) {
+ if (cursor.constant != Constant.NotAConstant) {
+ codeStream.newStringContatenation(); // new: java.lang.StringBuffer
+ codeStream.dup();
+ codeStream.ldc(cursor.constant.stringValue());
+ codeStream.invokeStringConcatenationStringConstructor();
+ // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V
+ break;
+ }
+ } else {
+ cursor.generateOptimizedStringConcatenationCreation(blockScope,
+ codeStream, cursor.implicitConversion &
+ TypeIds.COMPILE_TYPE_MASK);
+ break;
+ }
+ }
+ restart++;
+ if (restart == 0) { // reached the leftmost expression
+ cursor.left.generateOptimizedStringConcatenationCreation(
+ blockScope,
+ codeStream,
+ this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
+ }
+ int pcAux;
+ for (int i = restart; i < this.arity; i++) {
+ codeStream.recordPositionsFrom(pc,
+ (cursor = this.referencesTable[i]).left.sourceStart);
+ pcAux = codeStream.position;
+ cursor.right.generateOptimizedStringConcatenation(blockScope,
+ codeStream, cursor.right.implicitConversion &
+ TypeIds.COMPILE_TYPE_MASK);
+ codeStream.recordPositionsFrom(pcAux, cursor.right.sourceStart);
+ }
+ codeStream.recordPositionsFrom(pc, this.left.sourceStart);
+ pc = codeStream.position;
+ this.right.generateOptimizedStringConcatenation(
+ blockScope,
+ codeStream,
+ this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
+ codeStream.recordPositionsFrom(pc, this.right.sourceStart);
+ } else {
+ super.generateOptimizedStringConcatenationCreation(blockScope,
+ codeStream, typeID);
+ }
+ }
+}
+
+public StringBuffer printExpressionNoParenthesis(int indent,
+ StringBuffer output) {
+ // keep implementation in sync with
+ // BinaryExpression#printExpressionNoParenthesis and
+ // OperatorExpression#printExpression
+ if (this.referencesTable == null) {
+ return super.printExpressionNoParenthesis(indent, output);
+ }
+ String operatorString = operatorToString();
+ for (int i = this.arity - 1; i >= 0; i--) {
+ output.append('(');
+ }
+ output = this.referencesTable[0].left.
+ printExpression(indent, output);
+ for (int i = 0, end = this.arity;
+ i < end; i++) {
+ output.append(' ').append(operatorString).append(' ');
+ output = this.referencesTable[i].right.
+ printExpression(0, output);
+ output.append(')');
+ }
+ output.append(' ').append(operatorString).append(' ');
+ return this.right.printExpression(0, output);
+}
+
+public TypeBinding resolveType(BlockScope scope) {
+ // keep implementation in sync with BinaryExpression#resolveType
+ if (this.referencesTable == null) {
+ return super.resolveType(scope);
+ }
+ BinaryExpression cursor;
+ if ((cursor = this.referencesTable[0]).left instanceof CastExpression) {
+ cursor.left.bits |= ASTNode.DisableUnnecessaryCastCheck;
+ // will check later on
+ }
+ cursor.left.resolveType(scope);
+ for (int i = 0, end = this.arity; i < end; i ++) {
+ this.referencesTable[i].nonRecursiveResolveTypeUpwards(scope);
+ }
+ nonRecursiveResolveTypeUpwards(scope);
+ return this.resolvedType;
+}
+
+public void traverse(ASTVisitor visitor, BlockScope scope) {
+ if (this.referencesTable == null) {
+ super.traverse(visitor, scope);
+ } else {
+ if (visitor.visit(this, scope)) {
+ int restart;
+ for (restart = this.arity - 1;
+ restart >= 0;
+ restart--) {
+ if (!visitor.visit(
+ this.referencesTable[restart], scope)) {
+ visitor.endVisit(
+ this.referencesTable[restart], scope);
+ break;
+ }
+ }
+ restart++;
+ // restart now points to the deepest BE for which
+ // visit returned true, if any
+ if (restart == 0) {
+ this.referencesTable[0].left.traverse(visitor, scope);
+ }
+ for (int i = restart, end = this.arity;
+ i < end; i++) {
+ this.referencesTable[i].right.traverse(visitor, scope);
+ visitor.endVisit(this.referencesTable[i], scope);
+ }
+ this.right.traverse(visitor, scope);
+ }
+ visitor.endVisit(this, scope);
+ }
+}
+
+/**
+ * Change {@link #arityMax} if and as needed. The current policy is to double
+ * arityMax each time this method is called, until it reaches
+ * {@link #ARITY_MAX_MAX}. Other policies may consider incrementing it less
+ * agressively. Call only after an appropriate value has been assigned to
+ * {@link #left}.
+ */
+// more sophisticate increment policies would leverage the leftmost expression
+// to hold an indication of the number of uses of a given arityMax in a row
+public void tuneArityMax() {
+ if (this.arityMax < ARITY_MAX_MAX) {
+ this.arityMax *= 2;
+ }
+}
+}
#P org.eclipse.jdt.core.tests.compiler
Index: src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java,v
retrieving revision 1.13
diff -u -r1.13 FlowAnalysisTest.java
--- src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 19 Apr 2006 12:26:46 -0000 1.13
+++ src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 26 Jun 2006 10:14:23 -0000
@@ -752,6 +752,31 @@
"The local variable s may not have been initialized\n" +
"----------\n");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Non-recursive approach for deep binary expressions. Check that the
+// flow analysis doesn't break.
+public void test027() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String args[]) {\n" +
+ " String s;\n" +
+ " if (args.length == 0) {\n" +
+ " s = \"s\";\n" +
+ " } else {\n" +
+ " s = args[0];\n" +
+ " }\n" +
+ " System.out.println(s + \"-\" + s + \"-\" + s + \"-\" +\n" +
+ " s + \"-\" + s + \"-\" + s + \"-\" +\n" +
+ " s + \"-\" + s + \"-\" + s + \"-\" +\n" +
+ " s + \"-\" + s + \"-\" + s + \"-\" +\n" +
+ " s + \"-\" + s + \"-\" + s + \"-\");\n" +
+ " }\n" +
+ "}"
+ },
+ "s-s-s-s-s-s-s-s-s-s-s-s-s-s-s-");
+}
public static Class testClass() {
return FlowAnalysisTest.class;
}
Index: src/org/eclipse/jdt/core/tests/compiler/regression/XLargeTest.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/XLargeTest.java,v
retrieving revision 1.9
diff -u -r1.9 XLargeTest.java
--- src/org/eclipse/jdt/core/tests/compiler/regression/XLargeTest.java 29 Mar 2006 03:50:22 -0000 1.9
+++ src/org/eclipse/jdt/core/tests/compiler/regression/XLargeTest.java 26 Jun 2006 10:14:27 -0000
@@ -11,6 +11,7 @@
package org.eclipse.jdt.core.tests.compiler.regression;
import java.util.Map;
+import java.util.Random;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
@@ -3581,6 +3582,98 @@
},
"true");
}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Failed before using a non recursive implementation of deep binary
+// expressions.
+public void test010() {
+ StringBuffer sourceCode = new StringBuffer(
+ "public class X {\n" +
+ " void foo(String a, String b, String c, String d, String e) {\n" +
+ " String s = \n");
+ for (int i = 0; i < 350; i++) {
+ sourceCode.append(
+ " \"abcdef\" + a + b + c + d + e + " +
+ "\" ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno" +
+ "pqrstuvwxyzabcdefghijklmnopqrstuvwxyz\" +\n");
+ }
+ sourceCode.append(
+ " \"abcdef\" + a + b + c + d + e + \" ghijklmnopqrstuvwxyz" +
+ "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +
+ "abcdefghijklmnopqrstuvwxy12\";\n" +
+ " }\n" +
+ "}");
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ sourceCode.toString()
+ },
+ "");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if we hit the 64Kb limit on method code lenth in class files before
+// filling the stack
+// need to use a computed string (else this source file will get blown away
+// as well)
+public void test011() {
+ int length = 3 * 54 * 1000;
+ // the longer the slower, but still needs to reach the limit...
+ StringBuffer veryLongString = new StringBuffer(length + 20);
+ veryLongString.append('"');
+ Random random = new Random();
+ while (veryLongString.length() < length) {
+ veryLongString.append("\"+a+\"");
+ veryLongString.append(random.nextLong());
+ }
+ veryLongString.append('"');
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " void foo(String a, String b, String c, String d, String e) {\n" +
+ " String s = \n" +
+ veryLongString.toString() +
+ " + \"abcdef\" + a + b + c + d + e + \" ghiABCDEFGHIJKLMNOPQRSTUVWXYZjklmnopqrstuvwxyzabcdefghiABCDEFGHIJKLMNOPQRSTUVWXYZjklmnopqrstuvwxyzabcdefghiABCDEFGHIJKLMNOPQRSTUVWXYZjklmnopqrstuvwxyzabcdefghiABCDEFGHIJKLMNOPQRSTUVWXYZjklmnopqrstuvwxy12\";\n" +
+ " }\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 2)\n" +
+ " void foo(String a, String b, String c, String d, String e) {\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "The code of method foo(String, String, String, String, String) is " +
+ "exceeding the 65535 bytes limit\n" +
+ "----------\n");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// variant: right member of the topmost expression is left-deep
+public void test012() {
+ StringBuffer sourceCode = new StringBuffer(
+ "public class X {\n" +
+ " void foo(String a, String b, String c, String d, String e) {\n" +
+ " String s = a + (\n");
+ for (int i = 0; i < 1000; i++) {
+ sourceCode.append(
+ " \"abcdef\" + a + b + c + d + e + " +
+ "\" ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno" +
+ "pqrstuvwxyzabcdefghijklmnopqrstuvwxyz\" +\n");
+ }
+ sourceCode.append(
+ " \"abcdef\" + a + b + c + d + e + \" ghijklmnopqrstuvwxyz" +
+ "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +
+ "abcdefghijklmnopqrstuvwxy12\");\n" +
+ " }\n" +
+ "}");
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ sourceCode.toString()
+ },
+ "");
+}
+
public static Class testClass() {
return XLargeTest.class;
}
Index: src/org/eclipse/jdt/core/tests/compiler/regression/ASTImplTests.java
===================================================================
RCS file: src/org/eclipse/jdt/core/tests/compiler/regression/ASTImplTests.java
diff -N src/org/eclipse/jdt/core/tests/compiler/regression/ASTImplTests.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/jdt/core/tests/compiler/regression/ASTImplTests.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,800 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.compiler.regression;
+
+import junit.framework.Test;
+
+import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.CombinedBinaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation;
+import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+
+/**
+ * A tests series especially meant to validate the internals of our AST
+ * implementation.
+ */
+public class ASTImplTests extends AbstractRegressionTest {
+public ASTImplTests(String name) {
+ super(name);
+}
+
+ // Static initializer to specify tests subset using TESTS_* static variables
+ // All specified tests which does not belong to the class are skipped...
+ // Only the highest compliance level is run; add the VM argument
+ // -Dcompliance=1.4 (for example) to lower it if needed
+ static {
+// TESTS_NAMES = new String[] { "test2050" };
+// TESTS_NUMBERS = new int[] { 3 };
+// TESTS_NUMBERS = new int[] { 2999 };
+// TESTS_RANGE = new int[] { 2050, -1 };
+ }
+
+public static Test suite() {
+ return buildAllCompliancesTestSuite(testClass());
+}
+
+public static Class testClass() {
+ return ASTImplTests.class;
+}
+
+// Helper methods
+static Parser defaultParser = new Parser(
+ new ProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ new CompilerOptions(),
+ new DefaultProblemFactory()), false);
+public void runConformTest(String fileName, String fileContents,
+ Parser parser, ASTCollector visitor, String expected) {
+ CompilationUnit source =
+ new CompilationUnit(fileContents.toCharArray(), fileName, null);
+ CompilationResult compilationResult =
+ new CompilationResult(source, 1, 1, 10);
+ CompilationUnitDeclaration unit = parser.parse(source, compilationResult);
+ assertEquals(0, compilationResult.problemCount);
+ unit.traverse(visitor, unit.scope);
+ String result = visitor.result();
+ if (! expected.equals(result)) {
+ System.out.println(getClass().getName() + '#' + getName());
+ System.out.println("Expected:");
+ System.out.println(expected);
+ System.out.println("But was:");
+ System.out.println(result);
+ System.out.println("Cut and paste:");
+ System.out.println(Util.displayString(result, INDENT, SHIFT));
+ }
+ assertEquals(expected, result);
+}
+
+// AST implementation - visiting binary expressions
+public void test0001_regular_binary_expression() {
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " String s3 = \"s3\";\n" +
+ " String s4 = \"s4\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\" +\n" +
+ " s3 + \"l3\" + s4);\n" +
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTBinaryExpressionCollector(),
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v SL \"s2\"]\n" +
+ "[ev SL \"s2\"]\n" +
+ "[v SL \"s3\"]\n" +
+ "[ev SL \"s3\"]\n" +
+ "[v SL \"s4\"]\n" +
+ "[ev SL \"s4\"]\n" +
+ "[v BE ((((((s1 + \"l1\") + s...) + s4)]\n" +
+ "[v BE (((((s1 + \"l1\") + s2...+ \"l3\")]\n" +
+ "[v BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v BE ((s1 + \"l1\") + s2)]\n" +
+ "[v BE (s1 + \"l1\")]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[v SL \"l1\"]\n" +
+ "[ev SL \"l1\"]\n" +
+ "[ev BE (s1 + \"l1\")]\n" +
+ "[v SNR s2]\n" +
+ "[ev SNR s2]\n" +
+ "[ev BE ((s1 + \"l1\") + s2)]\n" +
+ "[v SL \"l2\"]\n" +
+ "[ev SL \"l2\"]\n" +
+ "[ev BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v SNR s3]\n" +
+ "[ev SNR s3]\n" +
+ "[ev BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v SL \"l3\"]\n" +
+ "[ev SL \"l3\"]\n" +
+ "[ev BE (((((s1 + \"l1\") + s2...+ \"l3\")]\n" +
+ "[v SNR s4]\n" +
+ "[ev SNR s4]\n" +
+ "[ev BE ((((((s1 + \"l1\") + s...) + s4)]\n");
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions
+public void test0002_combined_binary_expression() {
+ CombinedBinaryExpression.defaultArityMaxStartingValue = 3;
+ // one CBE each fourth BE
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " String s3 = \"s3\";\n" +
+ " String s4 = \"s4\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\" +\n" +
+ " s3 + \"l3\" + s4);\n" +
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTBinaryExpressionCollector() {
+ public void endVisit(BinaryExpression binaryExpression, BlockScope scope) {
+ if (binaryExpression instanceof CombinedBinaryExpression &&
+ ((CombinedBinaryExpression) binaryExpression).
+ referencesTable != null) {
+ this.collector.append("[ev CBE " +
+ cut(binaryExpression.toString()) + "]\n");
+ } else {
+ super.endVisit(binaryExpression, scope);
+ }
+ }
+ },
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v SL \"s2\"]\n" +
+ "[ev SL \"s2\"]\n" +
+ "[v SL \"s3\"]\n" +
+ "[ev SL \"s3\"]\n" +
+ "[v SL \"s4\"]\n" +
+ "[ev SL \"s4\"]\n" +
+ "[v BE ((((((s1 + \"l1\") + s...) + s4)]\n" +
+ "[v BE (((((s1 + \"l1\") + s2...+ \"l3\")]\n" +
+ "[v BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v BE ((s1 + \"l1\") + s2)]\n" +
+ "[v BE (s1 + \"l1\")]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[v SL \"l1\"]\n" +
+ "[ev SL \"l1\"]\n" +
+ "[ev BE (s1 + \"l1\")]\n" +
+ "[v SNR s2]\n" +
+ "[ev SNR s2]\n" +
+ "[ev BE ((s1 + \"l1\") + s2)]\n" +
+ "[v SL \"l2\"]\n" +
+ "[ev SL \"l2\"]\n" +
+ "[ev BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v SNR s3]\n" +
+ "[ev SNR s3]\n" +
+ "[ev CBE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v SL \"l3\"]\n" +
+ "[ev SL \"l3\"]\n" +
+ "[ev BE (((((s1 + \"l1\") + s2...+ \"l3\")]\n" +
+ "[v SNR s4]\n" +
+ "[ev SNR s4]\n" +
+ "[ev BE ((((((s1 + \"l1\") + s...) + s4)]\n");
+ CombinedBinaryExpression.defaultArityMaxStartingValue =
+ CombinedBinaryExpression.ARITY_MAX_MIN;
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions
+public void test0003_combined_binary_expression() {
+ Parser parser = new Parser(
+ new ProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ new CompilerOptions(),
+ new DefaultProblemFactory()), true); // optimize string literals
+ CombinedBinaryExpression.defaultArityMaxStartingValue = 2;
+ // one CBE each third BE - except the top one, which is degenerate (no
+ // references table)
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " String s3 = \"s3\";\n" +
+ " String s4 = \"s4\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\" +\n" +
+ " s3 + \"l3\" + s4);\n" +
+ " }\n" +
+ "}\n",
+ parser,
+ new ASTBinaryExpressionCollector() {
+ public void endVisit(BinaryExpression binaryExpression, BlockScope scope) {
+ if (binaryExpression instanceof CombinedBinaryExpression &&
+ ((CombinedBinaryExpression) binaryExpression).
+ referencesTable != null) {
+ this.collector.append("[ev CBE " +
+ cut(binaryExpression.toString()) + "]\n");
+ } else {
+ super.endVisit(binaryExpression, scope);
+ }
+ }
+ },
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v SL \"s2\"]\n" +
+ "[ev SL \"s2\"]\n" +
+ "[v SL \"s3\"]\n" +
+ "[ev SL \"s3\"]\n" +
+ "[v SL \"s4\"]\n" +
+ "[ev SL \"s4\"]\n" +
+ "[v BE ((((((s1 + \"l1\") + s...) + s4)]\n" +
+ "[v BE (((((s1 + \"l1\") + s2...+ \"l3\")]\n" +
+ "[v BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v BE ((s1 + \"l1\") + s2)]\n" +
+ "[v BE (s1 + \"l1\")]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[v SL \"l1\"]\n" +
+ "[ev SL \"l1\"]\n" +
+ "[ev BE (s1 + \"l1\")]\n" +
+ "[v SNR s2]\n" +
+ "[ev SNR s2]\n" +
+ "[ev BE ((s1 + \"l1\") + s2)]\n" +
+ "[v SL \"l2\"]\n" +
+ "[ev SL \"l2\"]\n" +
+ "[ev CBE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v SNR s3]\n" +
+ "[ev SNR s3]\n" +
+ "[ev BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v SL \"l3\"]\n" +
+ "[ev SL \"l3\"]\n" +
+ "[ev BE (((((s1 + \"l1\") + s2...+ \"l3\")]\n" +
+ "[v SNR s4]\n" +
+ "[ev SNR s4]\n" +
+ "[ev BE ((((((s1 + \"l1\") + s...) + s4)]\n");
+ CombinedBinaryExpression.defaultArityMaxStartingValue =
+ CombinedBinaryExpression.ARITY_MAX_MIN;
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions - effect of a literal at the start with
+// string literal optimization
+public void test0004_combined_binary_expression() {
+ Parser parser = new Parser(
+ new ProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ new CompilerOptions(),
+ new DefaultProblemFactory()), true); // optimize string literals
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " System.out.println(\"l\" + \"1\" + s1);\n" +
+ // "l" + "1" is collapsed into "l1" without affecting binary
+ // expressions: only one BE
+ " }\n" +
+ "}\n",
+ parser,
+ new ASTBinaryExpressionCollector(),
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v BE (ExtendedStringLiter...} + s1)]\n" +
+ "[v ESL ExtendedStringLiteral{l1}]\n" +
+ "[ev ESL ExtendedStringLiteral{l1}]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[ev BE (ExtendedStringLiter...} + s1)]\n");
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions - effect of a literal at the start without
+// string literals optimization
+public void test0005_combined_binary_expression() {
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " System.out.println(\"l\" + \"1\" + s1);\n" +
+ // "l" + "1" is handled by a string literal concatenation without
+ // affecting binary expressions: only one BE
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTBinaryExpressionCollector(),
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v BE (StringLiteralConcat...} + s1)]\n" +
+ "[v SLC StringLiteralConcate...\n" +
+ "\"1\"+\n" +
+ "}]\n" +
+ "[v SL \"l\"]\n" +
+ "[ev SL \"l\"]\n" +
+ "[v SL \"1\"]\n" +
+ "[ev SL \"1\"]\n" +
+ "[ev SLC StringLiteralConcate...\n" +
+ "\"1\"+\n" +
+ "}]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[ev BE (StringLiteralConcat...} + s1)]\n");
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions - cutting the traversal half-way down
+public void test0006_combined_binary_expression() {
+ CombinedBinaryExpression.defaultArityMaxStartingValue = 1;
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " String s3 = \"s3\";\n" +
+ " String s4 = \"s4\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\" +\n" +
+ " s3 + s1 + s4);\n" +
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTBinaryExpressionCollector() {
+ public boolean visit(BinaryExpression binaryExpression, BlockScope scope) {
+ super.visit(binaryExpression, scope);
+ if (binaryExpression.right instanceof StringLiteral) {
+ return false;
+ }
+ return true;
+ }
+ },
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v SL \"s2\"]\n" +
+ "[ev SL \"s2\"]\n" +
+ "[v SL \"s3\"]\n" +
+ "[ev SL \"s3\"]\n" +
+ "[v SL \"s4\"]\n" +
+ "[ev SL \"s4\"]\n" +
+ "[v BE ((((((s1 + \"l1\") + s...) + s4)]\n" +
+ "[v BE (((((s1 + \"l1\") + s2...) + s1)]\n" +
+ "[v BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[ev BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v SNR s3]\n" +
+ "[ev SNR s3]\n" +
+ "[ev BE ((((s1 + \"l1\") + s2)...) + s3)]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[ev BE (((((s1 + \"l1\") + s2...) + s1)]\n" +
+ "[v SNR s4]\n" +
+ "[ev SNR s4]\n" +
+ "[ev BE ((((((s1 + \"l1\") + s...) + s4)]\n");
+ CombinedBinaryExpression.defaultArityMaxStartingValue =
+ CombinedBinaryExpression.ARITY_MAX_MIN;
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions - cutting the traversal right away
+public void test0007_combined_binary_expression() {
+ CombinedBinaryExpression.defaultArityMaxStartingValue = 4;
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " String s3 = \"s3\";\n" +
+ " String s4 = \"s4\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\" +\n" +
+ " s3 + \"l3\" + s4);\n" +
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTBinaryExpressionCollector() {
+ public boolean visit(BinaryExpression binaryExpression, BlockScope scope) {
+ super.visit(binaryExpression, scope);
+ return false;
+ }
+ },
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v SL \"s2\"]\n" +
+ "[ev SL \"s2\"]\n" +
+ "[v SL \"s3\"]\n" +
+ "[ev SL \"s3\"]\n" +
+ "[v SL \"s4\"]\n" +
+ "[ev SL \"s4\"]\n" +
+ "[v BE ((((((s1 + \"l1\") + s...) + s4)]\n" +
+ "[ev BE ((((((s1 + \"l1\") + s...) + s4)]\n");
+ CombinedBinaryExpression.defaultArityMaxStartingValue =
+ CombinedBinaryExpression.ARITY_MAX_MIN;
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions - case of one-deep expression
+public void test0008_combined_binary_expression() {
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\");\n" +
+ " System.out.println(s1 + s2);\n" +
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTBinaryExpressionCollector() {
+ public void endVisit(BinaryExpression binaryExpression, BlockScope scope) {
+ if (binaryExpression instanceof CombinedBinaryExpression) {
+ this.collector.append("[ev CBE " +
+ cut(binaryExpression.toString()) + "]\n");
+ } else {
+ super.endVisit(binaryExpression, scope);
+ }
+ }
+ },
+ "[v SL \"s1\"]\n" +
+ "[ev SL \"s1\"]\n" +
+ "[v SL \"s2\"]\n" +
+ "[ev SL \"s2\"]\n" +
+ "[v BE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v BE ((s1 + \"l1\") + s2)]\n" +
+ "[v BE (s1 + \"l1\")]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[v SL \"l1\"]\n" +
+ "[ev SL \"l1\"]\n" +
+ "[ev BE (s1 + \"l1\")]\n" +
+ "[v SNR s2]\n" +
+ "[ev SNR s2]\n" +
+ "[ev BE ((s1 + \"l1\") + s2)]\n" +
+ "[v SL \"l2\"]\n" +
+ "[ev SL \"l2\"]\n" +
+ "[ev CBE (((s1 + \"l1\") + s2) + \"l2\")]\n" +
+ "[v BE (s1 + s2)]\n" +
+ "[v SNR s1]\n" +
+ "[ev SNR s1]\n" +
+ "[v SNR s2]\n" +
+ "[ev SNR s2]\n" +
+ "[ev BE (s1 + s2)]\n");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if the generated code is OK when leveraging CombinedBinaryExpression
+public void test0009_combined_binary_expression() {
+ assertEquals(20, CombinedBinaryExpression.ARITY_MAX_MIN);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void main(String args[]) {\n" +
+ " final int max = 30; \n" +
+ " String s[] = new String[max];\n" +
+ " for (int i = 0; i < max; i++) {\n" +
+ " s[i] = \"a\";\n" +
+ " }\n" +
+ " foo(s);\n" +
+ "}\n" +
+ "static void foo (String s[]) {\n" +
+ " System.out.println(\n" +
+ " s[0] + s[1] + s[2] + s[3] + s[4] + s[5] + s[6] + \n" +
+ " s[7] + s[8] + s[9] + s[10] + s[11] + s[12] + s[13] +\n" +
+ " s[14] + s[15] + s[16] + s[17] + s[18] + s[19] + \n" +
+ " s[20] + s[21] + s[22] + s[23] + s[24] + s[25] + \n" +
+ " s[26] + s[27] + s[28] + s[29]\n" +
+ " );\n" +
+ "}\n" +
+ "}"},
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if the generated code is OK when leveraging CombinedBinaryExpression
+// variant involving constant binary expressions deep in the tree
+public void test0010_combined_binary_expression() {
+ assertEquals(20, CombinedBinaryExpression.ARITY_MAX_MIN);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void main(String args[]) {\n" +
+ " final int max = 30; \n" +
+ " String s[] = new String[max];\n" +
+ " for (int i = 0; i < max; i++) {\n" +
+ " s[i] = \"a\";\n" +
+ " }\n" +
+ " foo(s);\n" +
+ "}\n" +
+ "static void foo (String s[]) {\n" +
+ " final String c = \"a\";" +
+ " System.out.println(\n" +
+ " c + c + c + c + s[4] + s[5] + s[6] + s[7] + s[8] + \n" +
+ " s[9] + s[10] + s[11] + s[12] + s[13] + s[14] + \n" +
+ " s[15] + s[16] + s[17] + s[18] + s[19] + s[20] + \n" +
+ " s[21] + s[22] + s[23] + s[24] + s[25] + s[26] + \n" +
+ " s[27] + s[28] + s[29]\n" +
+ " );\n" +
+ "}\n" +
+ "}"
+ },
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if the generated code is OK when leveraging CombinedBinaryExpression
+// variant involving a constant combined binary expression
+public void test0011_combined_binary_expression() {
+ assertEquals(20, CombinedBinaryExpression.ARITY_MAX_MIN);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void main(String args[]) {\n" +
+ " final int max = 30; \n" +
+ " String s[] = new String[max];\n" +
+ " for (int i = 0; i < max; i++) {\n" +
+ " s[i] = \"a\";\n" +
+ " }\n" +
+ " foo(s);\n" +
+ "}\n" +
+ "static void foo (String s[]) {\n" +
+ " final String c = \"a\";" +
+ " System.out.println(\n" +
+ " c + c + c + c + c + c + c + c + c + c + \n" +
+ " c + c + c + c + c + c + c + c + c + c + \n" +
+ " c + c + s[22] + s[23] + s[24] + s[25] + s[26] + \n" +
+ " s[27] + s[28] + s[29]\n" +
+ " );\n" +
+ "}\n" +
+ "}"
+ },
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+}
+
+// AST implementation - visiting binary expressions
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// Adding combined binary expressions - checking recursive print
+public void test_0012_combined_binary_expression() {
+ CombinedBinaryExpression.defaultArityMaxStartingValue = 2;
+ runConformTest(
+ "X.java",
+ "public class X {\n" +
+ " void foo() {\n" +
+ " String s1 = \"s1\";\n" +
+ " String s2 = \"s2\";\n" +
+ " String s3 = \"s3\";\n" +
+ " String s4 = \"s4\";\n" +
+ " System.out.println(s1 + \"l1\" + s2 + \"l2\" +\n" +
+ " s3 + s1 + s4);\n" +
+ " }\n" +
+ "}\n",
+ defaultParser,
+ new ASTCollector() {
+ public boolean visit(BinaryExpression binaryExpression,
+ BlockScope scope) {
+ super.visit(binaryExpression, scope);
+ this.collector.append(binaryExpression);
+ return true;
+ }
+ },
+ "((((((s1 + \"l1\") + s2) + \"l2\") + s3) + s1) + s4)(((((s1 + \"l1\")" +
+ " + s2) + \"l2\") + s3) + s1)((((s1 + \"l1\") + s2) + \"l2\") + s3)" +
+ "(((s1 + \"l1\") + s2) + \"l2\")((s1 + \"l1\") + s2)(s1 + \"l1\")");
+ CombinedBinaryExpression.defaultArityMaxStartingValue =
+ CombinedBinaryExpression.ARITY_MAX_MIN;
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if the generated code is OK when leveraging CombinedBinaryExpression
+// variant involving a left-deep right expression at the topmost level
+public void test0013_combined_binary_expression() {
+ assertEquals(20, CombinedBinaryExpression.ARITY_MAX_MIN);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void main(String args[]) {\n" +
+ " final int max = 30; \n" +
+ " String s[] = new String[max];\n" +
+ " for (int i = 0; i < max; i++) {\n" +
+ " s[i] = \"a\";\n" +
+ " }\n" +
+ " foo(s);\n" +
+ "}\n" +
+ "static void foo (String s[]) {\n" +
+ " System.out.println(\n" +
+ " \"b\" + (s[0] + s[1] + s[2] + s[3] + s[4] + s[5] + s[6] + \n" +
+ " s[7] + s[8] + s[9] + s[10] + s[11] + s[12] + s[13] +\n" +
+ " s[14] + s[15] + s[16] + s[17] + s[18] + s[19] + \n" +
+ " s[20] + s[21] + s[22] + s[23] + s[24] + s[25] + \n" +
+ " s[26] + s[27] + s[28] + s[29])\n" +
+ " );\n" +
+ "}\n" +
+ "}"
+ },
+ "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if the generated code is OK when leveraging CombinedBinaryExpression
+// variant involving a left-deep right expression at the topmost level, with
+// a constant high in tree
+public void test0014_combined_binary_expression() {
+ assertEquals(20, CombinedBinaryExpression.ARITY_MAX_MIN);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void main(String args[]) {\n" +
+ " final int max = 30; \n" +
+ " String s[] = new String[max];\n" +
+ " for (int i = 0; i < max; i++) {\n" +
+ " s[i] = \"a\";\n" +
+ " }\n" +
+ " foo(s);\n" +
+ "}\n" +
+ "static void foo (String s[]) {\n" +
+ " final String c = \"c\";\n" +
+ " System.out.println(\n" +
+ " \"b\" + \n" +
+ " (c + c + c + c + c + c + c + c + c + c + \n" +
+ " c + c + c + c + c + c + c + c + c + c + \n" +
+ " c + c + s[0])\n" +
+ " );\n" +
+ "}\n" +
+ "}"
+ },
+ "bcccccccccccccccccccccca");
+}
+
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102728
+// check if the generated code is OK when leveraging CombinedBinaryExpression
+// variant involving a left-deep right expression at the topmost level, with
+// a constant low in tree
+public void test0015_combined_binary_expression() {
+ assertEquals(20, CombinedBinaryExpression.ARITY_MAX_MIN);
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void main(String args[]) {\n" +
+ " final int max = 30; \n" +
+ " String s[] = new String[max];\n" +
+ " for (int i = 0; i < max; i++) {\n" +
+ " s[i] = \"a\";\n" +
+ " }\n" +
+ " foo(s);\n" +
+ "}\n" +
+ "static void foo (String s[]) {\n" +
+ " final String c = \"c\";\n" +
+ " System.out.println(\n" +
+ " \"b\" + \n" +
+ " (c + c + c + c + c + c + c + c + c + c + \n" +
+ " c + c + c + c + c + c + c + c + c + c + \n" +
+ " s[0] + s[1] + s[2])\n" +
+ " );\n" +
+ "}\n" +
+ "}"
+ },
+ "bccccccccccccccccccccaaa");
+}
+}
+
+// Helper classes: define visitors leveraged by some tests
+class ASTCollector extends ASTVisitor {
+ StringBuffer collector = new StringBuffer();
+public String result() {
+ return this.collector.toString();
+}
+}
+
+class ASTBinaryExpressionCollector extends ASTCollector {
+static final int LIMIT = 30;
+// help limit the output in length by suppressing the middle
+// part of strings which length exceeds LIMIT
+String cut(String source) {
+ int length;
+ if ((length = source.length()) > LIMIT) {
+ StringBuffer result = new StringBuffer(length);
+ result.append(source.substring(0, LIMIT - 10));
+ result.append("...");
+ result.append(source.substring(length - 7, length));
+ return result.toString();
+ } else {
+ return source;
+ }
+}
+public void endVisit(BinaryExpression binaryExpression, BlockScope scope) {
+ this.collector.append("[ev BE " + cut(binaryExpression.toString()) + "]\n");
+ super.endVisit(binaryExpression, scope);
+}
+
+public void endVisit(CharLiteral charLiteral, BlockScope scope) {
+ this.collector.append("[ev CL " + cut(charLiteral.toString()) + "]\n");
+ super.endVisit(charLiteral, scope);
+}
+
+public void endVisit(ExtendedStringLiteral literal, BlockScope scope) {
+ this.collector.append("[ev ESL " + cut(literal.toString()) + "]\n");
+ super.endVisit(literal, scope);
+}
+
+public void endVisit(SingleNameReference singleNameReference,
+ BlockScope scope) {
+ this.collector.append("[ev SNR " + cut(singleNameReference.toString()) +
+ "]\n");
+ super.endVisit(singleNameReference, scope);
+}
+
+public void endVisit(StringLiteral stringLiteral, BlockScope scope) {
+ this.collector.append("[ev SL " + cut(stringLiteral.toString()) + "]\n");
+ super.endVisit(stringLiteral, scope);
+}
+
+public void endVisit(StringLiteralConcatenation literal, BlockScope scope) {
+ this.collector.append("[ev SLC " + cut(literal.toString()) + "]\n");
+ super.endVisit(literal, scope);
+}
+
+public boolean visit(BinaryExpression binaryExpression, BlockScope scope) {
+ this.collector.append("[v BE " + cut(binaryExpression.toString()) + "]\n");
+ return super.visit(binaryExpression, scope);
+}
+
+public boolean visit(CharLiteral charLiteral, BlockScope scope) {
+ this.collector.append("[v CL " + cut(charLiteral.toString()) + "]\n");
+ return super.visit(charLiteral, scope);
+}
+
+public boolean visit(ExtendedStringLiteral literal, BlockScope scope) {
+ this.collector.append("[v ESL " + cut(literal.toString()) + "]\n");
+ return super.visit(literal, scope);
+}
+
+public boolean visit(SingleNameReference singleNameReference,
+ BlockScope scope) {
+ this.collector.append("[v SNR " + cut(singleNameReference.toString()) +
+ "]\n");
+ return super.visit(singleNameReference, scope);
+}
+
+public boolean visit(StringLiteral stringLiteral, BlockScope scope) {
+ this.collector.append("[v SL " + cut(stringLiteral.toString()) + "]\n");
+ return super.visit(stringLiteral, scope);
+}
+
+public boolean visit(StringLiteralConcatenation literal, BlockScope scope) {
+ this.collector.append("[v SLC " + cut(literal.toString()) + "]\n");
+ return super.visit(literal, scope);
+}
+}