Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 45289 Details for
Bug 102728
[compiler] Reduce the stack depth demands of extended string concatenation ASTs
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
Suggested fix plus test cases
org.eclipse.jdt.core_01.txt (text/plain), 64.64 KB, created by
Maxime Daniel
on 2006-06-26 06:17:36 EDT
(
hide
)
Description:
Suggested fix plus test cases
Filename:
MIME Type:
Creator:
Maxime Daniel
Created:
2006-06-26 06:17:36 EDT
Size:
64.64 KB
patch
obsolete
>### 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.<br> >+ * Notes: >+ * <ul> >+ * <li>CombinedBinaryExpression is not meant to behave in other ways than >+ * BinaryExpression in any observable respect;</li> >+ * <li>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;</li> >+ * <li>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.</li> >+ * </ul> >+ */ >+public class CombinedBinaryExpression extends BinaryExpression { >+ >+ /** >+ * The number of consecutive binary expressions of this' left branch that >+ * bear the same operator as this.<br> >+ * Notes: >+ * <ul><li>the presence of a CombinedBinaryExpression instance resets >+ * arity, even when its operator is compatible;</li> >+ * <li>this property is maintained by the parser.</li> >+ * </ul> >+ */ >+ 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.<init>(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); >+} >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 102728
:
45289
|
45372