### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: dom/org/eclipse/jdt/core/dom/ASTParser.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java,v retrieving revision 1.51 diff -u -r1.51 ASTParser.java --- dom/org/eclipse/jdt/core/dom/ASTParser.java 23 Jan 2006 10:08:24 -0000 1.51 +++ dom/org/eclipse/jdt/core/dom/ASTParser.java 8 Feb 2006 11:49:29 -0000 @@ -970,7 +970,7 @@ } } } - rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation); + rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation, data); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return block; @@ -993,7 +993,7 @@ compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); if (expression != null) { Expression expression2 = converter.convert(expression); - rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation); + rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation, null); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return expression2; @@ -1016,7 +1016,7 @@ compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); if (nodes != null) { TypeDeclaration typeDeclaration = converter.convert(nodes); - rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation); + rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation, null); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return typeDeclaration; @@ -1033,14 +1033,14 @@ throw new IllegalStateException(); } - private void propagateErrors(ASTNode astNode, IProblem[] problems) { + private void propagateErrors(ASTNode astNode, IProblem[] problems, RecoveryScannerData data) { ASTSyntaxErrorPropagator syntaxErrorPropagator = new ASTSyntaxErrorPropagator(problems); astNode.accept(syntaxErrorPropagator); - ASTRecoveryPropagator recoveryPropagator = new ASTRecoveryPropagator(problems); + ASTRecoveryPropagator recoveryPropagator = new ASTRecoveryPropagator(problems, data); astNode.accept(recoveryPropagator); } - private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation) { + private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation, RecoveryScannerData data) { final int problemsCount = recordedParsingInformation.problemsCount; switch(node.getNodeType()) { case ASTNode.BLOCK : @@ -1050,7 +1050,7 @@ // propagate and record problems final IProblem[] problems = recordedParsingInformation.problems; for (int i = 0, max = block.statements().size(); i < max; i++) { - propagateErrors((ASTNode) block.statements().get(i), problems); + propagateErrors((ASTNode) block.statements().get(i), problems, data); } compilationUnit.setProblems(problems); } @@ -1068,7 +1068,7 @@ // propagate and record problems final IProblem[] problems = recordedParsingInformation.problems; for (int i = 0, max = typeDeclaration.bodyDeclarations().size(); i < max; i++) { - propagateErrors((ASTNode) typeDeclaration.bodyDeclarations().get(i), problems); + propagateErrors((ASTNode) typeDeclaration.bodyDeclarations().get(i), problems, data); } compilationUnit.setProblems(problems); } @@ -1081,7 +1081,7 @@ if (problemsCount != 0) { // propagate and record problems final IProblem[] problems = recordedParsingInformation.problems; - propagateErrors(expression, problems); + propagateErrors(expression, problems, data); compilationUnit.setProblems(problems); } ExpressionStatement expressionStatement = ast.newExpressionStatement(expression); Index: dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java,v retrieving revision 1.1 diff -u -r1.1 ASTRecoveryPropagator.java --- dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java 17 Jan 2006 18:44:23 -0000 1.1 +++ dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java 8 Feb 2006 11:49:29 -0000 @@ -11,27 +11,282 @@ package org.eclipse.jdt.core.dom; +import java.util.Vector; + import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToIntArray; /** * Internal AST visitor for propagating syntax errors. */ class ASTRecoveryPropagator extends DefaultASTVisitor { + private static final int NOTHING = -1; + HashtableOfObjectToIntArray endingTokens = new HashtableOfObjectToIntArray(); + { + this.endingTokens.put(AnonymousClassDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(ArrayAccess.class, new int[]{TerminalTokens.TokenNameRBRACKET}); + this.endingTokens.put(ArrayCreation.class, new int[]{NOTHING, TerminalTokens.TokenNameRBRACKET}); + this.endingTokens.put(ArrayInitializer.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(ArrayType.class, new int[]{TerminalTokens.TokenNameRBRACKET}); + this.endingTokens.put(AssertStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(Block.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(BooleanLiteral.class, new int[]{TerminalTokens.TokenNamefalse, TerminalTokens.TokenNametrue}); + this.endingTokens.put(BreakStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(CharacterLiteral.class, new int[]{TerminalTokens.TokenNameCharacterLiteral}); + this.endingTokens.put(ClassInstanceCreation.class, new int[]{TerminalTokens.TokenNameRBRACE, TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(ConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ContinueStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(DoStatement.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(EmptyStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ExpressionStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(FieldDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ImportDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(Initializer.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(MethodDeclaration.class, new int[]{NOTHING, TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(MethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(NullLiteral.class, new int[]{TerminalTokens.TokenNamenull}); + this.endingTokens.put(NumberLiteral.class, new int[]{TerminalTokens.TokenNameIntegerLiteral, TerminalTokens.TokenNameLongLiteral, TerminalTokens.TokenNameFloatingPointLiteral, TerminalTokens.TokenNameDoubleLiteral}); + this.endingTokens.put(PackageDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ParenthesizedExpression.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(PostfixExpression.class, new int[]{TerminalTokens.TokenNamePLUS_PLUS, TerminalTokens.TokenNameMINUS_MINUS}); + this.endingTokens.put(PrimitiveType.class, new int[]{TerminalTokens.TokenNamebyte, TerminalTokens.TokenNameshort, TerminalTokens.TokenNamechar, TerminalTokens.TokenNameint, TerminalTokens.TokenNamelong, TerminalTokens.TokenNamefloat, TerminalTokens.TokenNameboolean, TerminalTokens.TokenNamedouble, TerminalTokens.TokenNamevoid}); + this.endingTokens.put(ReturnStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(SimpleName.class, new int[]{TerminalTokens.TokenNameIdentifier}); + this.endingTokens.put(SingleVariableDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(StringLiteral.class, new int[]{TerminalTokens.TokenNameStringLiteral}); + this.endingTokens.put(SuperConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(SuperMethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(SwitchCase.class, new int[]{TerminalTokens.TokenNameCOLON}); + this.endingTokens.put(SwitchStatement.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(SynchronizedStatement.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(ThisExpression.class, new int[]{TerminalTokens.TokenNamethis}); + this.endingTokens.put(ThrowStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(TypeDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(TypeLiteral.class, new int[]{TerminalTokens.TokenNameclass}); + this.endingTokens.put(VariableDeclarationStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + } + private IProblem[] problems; + private boolean[] usedOrIrrelevantProblems; + + private RecoveryScannerData data; + private int blockDepth = 0; + private int lastEnd; + + private int[] insertedTokensKind; + private int[] insertedTokensPosition; + private boolean[] insertedTokensFlagged; + + private boolean[] removedTokensFlagged; + private boolean[] replacedTokensFlagged; + + private Vector stack = new Vector(); - ASTRecoveryPropagator(IProblem[] problems) { + ASTRecoveryPropagator(IProblem[] problems, RecoveryScannerData data) { // visit Javadoc.tags() as well this.problems = problems; + this.usedOrIrrelevantProblems = new boolean[problems.length]; + + this.data = data; + + if(this.data != null) { + + int length = 0; + for (int i = 0; i < data.insertedTokensPtr + 1; i++) { + length += data.insertedTokens[i].length; + } + this.insertedTokensKind = new int[length]; + this.insertedTokensPosition = new int[length]; + this.insertedTokensFlagged = new boolean[length]; + int tokenCount = 0; + for (int i = 0; i < data.insertedTokensPtr + 1; i++) { + for (int j = 0; j < data.insertedTokens[i].length; j++) { + this.insertedTokensKind[tokenCount] = data.insertedTokens[i][j]; + this.insertedTokensPosition[tokenCount] = data.insertedTokensPosition[i]; + tokenCount++; + } + } + + if(data.removedTokensPtr != -1) { + this.removedTokensFlagged = new boolean[data.removedTokensPtr + 1]; + } + if(data.replacedTokensPtr != -1) { + this.replacedTokensFlagged = new boolean[data.replacedTokensPtr + 1]; + } + } + } + + public void endVisit(Block node) { + this.blockDepth--; + if(this.blockDepth <= 0) { + flagNodeWithInsertedTokens(); + } + super.endVisit(node); + } + + + + public boolean visit(Block node) { + boolean visitChildren = super.visit(node); + this.blockDepth++; + return visitChildren; } protected boolean visitNode(ASTNode node) { - return checkAndTagAsMalformed(node); + if(this.blockDepth > 0) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + + // continue to visit the node only if it contains tokens modifications + + if(this.insertedTokensFlagged != null) { + for (int i = 0; i < this.insertedTokensFlagged.length; i++) { + if(this.insertedTokensPosition[i] >= start && + this.insertedTokensPosition[i] <= end) { + return true; + } + } + } + + if(this.removedTokensFlagged != null) { + for (int i = 0; i <= this.data.removedTokensPtr; i++) { + if(this.data.removedTokensStart[i] >= start && + this.data.removedTokensEnd[i] <= end) { + return true; + } + } + } + + if(this.replacedTokensFlagged != null) { + for (int i = 0; i <= this.data.removedTokensPtr; i++) { + if(this.data.replacedTokensStart[i] >= start && + this.data.replacedTokensEnd[i] <= end) { + return true; + } + } + } + + return false; + } + return true; + } + + protected void endVisitNode(ASTNode node) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + + // is inside diet part of the ast + if(this.blockDepth < 1) { + if(this.markIncludedProblems(start, end)) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + } + } else { + this.markIncludedProblems(start, end); + + if(this.insertedTokensFlagged != null) { + if(this.lastEnd != end) { + flagNodeWithInsertedTokens(); + } + this.stack.add(node); + } + + if(this.removedTokensFlagged != null) { + for (int i = 0; i <= this.data.removedTokensPtr; i++) { + if(!this.removedTokensFlagged[i] && + this.data.removedTokensStart[i] >= start && + this.data.removedTokensEnd[i] <= end) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + this.removedTokensFlagged[i] = true; + } + } + } + + if(this.replacedTokensFlagged != null) { + for (int i = 0; i <= this.data.replacedTokensPtr; i++) { + if(!this.replacedTokensFlagged[i] && + this.data.replacedTokensStart[i] >= start && + this.data.replacedTokensEnd[i] <= end) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + this.replacedTokensFlagged[i] = true; + } + } + } + } + this.lastEnd = end; } - private boolean checkAndTagAsMalformed(ASTNode node) { - boolean tagWithErrors = false; - search: for (int i = 0, max = this.problems.length; i < max; i++) { + private void flagNodeWithInsertedTokens() { + if(this.insertedTokensKind != null && this.insertedTokensKind.length > 0) { + int s = this.stack.size(); + for (int i = s - 1; i > -1; i--) { + flagNodesWithInsertedTokensAtEnd((ASTNode)this.stack.get(i)); + } + for (int i = 0; i < s; i++) { + flagNodesWithInsertedTokensInside((ASTNode)this.stack.get(i)); + } + this.stack = new Vector(); + } + } + + private boolean flagNodesWithInsertedTokensAtEnd(ASTNode node) { + int[] expectedEndingToken = this.endingTokens.get(node.getClass()); + if (expectedEndingToken != null) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + + boolean flagParent = false; + done : for (int i = this.insertedTokensKind.length - 1; i > -1 ; i--) { + if(!this.insertedTokensFlagged[i] && + this.insertedTokensPosition[i] == end){ + this.insertedTokensFlagged[i] = true; + for (int j = 0; j < expectedEndingToken.length; j++) { + if(expectedEndingToken[j] == this.insertedTokensKind[i]) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + break done; + } + } + flagParent = true; + } + } + + if(flagParent) { + ASTNode parent = node.getParent(); + while (parent != null) { + parent.setFlags(node.getFlags() | ASTNode.RECOVERED); + if((parent.getStartPosition() + parent.getLength() - 1) != end) { + parent = null; + } else { + parent = parent.getParent(); + } + } + } + } + return true; + } + + private boolean flagNodesWithInsertedTokensInside(ASTNode node) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + for (int i = 0; i < this.insertedTokensKind.length; i++) { + if(!this.insertedTokensFlagged[i] && + start <= this.insertedTokensPosition[i] && + this.insertedTokensPosition[i] < end){ + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + this.insertedTokensFlagged[i] = true; + } + } + return true; + } + + private boolean markIncludedProblems(int start, int end) { + boolean foundProblems = false; + next: for (int i = 0, max = this.problems.length; i < max; i++) { IProblem problem = this.problems[i]; + + if(this.usedOrIrrelevantProblems[i]) continue next; + switch(problem.getID()) { case IProblem.ParsingErrorOnKeywordNoSuggestion : case IProblem.ParsingErrorOnKeyword : @@ -64,18 +319,19 @@ case IProblem.InvalidDigit : break; default: - continue search; + this.usedOrIrrelevantProblems[i] = true; + continue next; + } + int problemStart = problem.getSourceStart(); int problemEnd = problem.getSourceEnd(); - int start = node.getStartPosition(); - int end = start + node.getLength(); if ((start <= problemStart) && (problemStart <= end) || (start <= problemEnd) && (problemEnd <= end)) { - node.setFlags(node.getFlags() | ASTNode.RECOVERED); - tagWithErrors = true; + this.usedOrIrrelevantProblems[i] = true; + foundProblems = true; } } - return tagWithErrors; + return foundProblems; } } Index: dom/org/eclipse/jdt/core/dom/ASTConverter.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java,v retrieving revision 1.228 diff -u -r1.228 ASTConverter.java --- dom/org/eclipse/jdt/core/dom/ASTConverter.java 6 Feb 2006 16:50:05 -0000 1.228 +++ dom/org/eclipse/jdt/core/dom/ASTConverter.java 8 Feb 2006 11:49:28 -0000 @@ -114,7 +114,7 @@ } } } - if(this.scanner instanceof RecoveryScanner && ((RecoveryScanner)this.scanner).isFakeTokenInserted()) { + if(this.scanner instanceof RecoveryScanner && ((RecoveryScanner)this.scanner).isInsertedToken()) { expression.sourceEnd = this.scanner.startPosition; } else { expression.sourceEnd = this.scanner.startPosition - 1; @@ -1196,7 +1196,8 @@ public CompilationUnit convert(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration unit, char[] source) { if(unit.compilationResult.recoveryScannerData != null) { - this.scanner = new RecoveryScanner(this.scanner, unit.compilationResult.recoveryScannerData.removeUnused()); + RecoveryScanner recoveryScanner = new RecoveryScanner(this.scanner, unit.compilationResult.recoveryScannerData.removeUnused()); + this.scanner = recoveryScanner; this.docParser.scanner = this.scanner; } this.compilationUnitSource = source; @@ -1257,7 +1258,8 @@ } ASTSyntaxErrorPropagator syntaxErrorPropagator = new ASTSyntaxErrorPropagator(resizedProblems); compilationUnit.accept(syntaxErrorPropagator); - ASTRecoveryPropagator recoveryPropagator = new ASTRecoveryPropagator(resizedProblems); + ASTRecoveryPropagator recoveryPropagator = + new ASTRecoveryPropagator(resizedProblems, unit.compilationResult.recoveryScannerData); compilationUnit.accept(recoveryPropagator); compilationUnit.setProblems(resizedProblems); } @@ -4125,13 +4127,13 @@ balance --; break; case TerminalTokens.TokenNameCOMMA : - if(this.scanner instanceof RecoveryScanner && ((RecoveryScanner)this.scanner).isFakeTokenInserted()) { + if(this.scanner instanceof RecoveryScanner && ((RecoveryScanner)this.scanner).isInsertedToken()) { return this.scanner.startPosition; } if (balance == 0) return this.scanner.startPosition - 1; break; case TerminalTokens.TokenNameSEMICOLON : - if(this.scanner instanceof RecoveryScanner && ((RecoveryScanner)this.scanner).isFakeTokenInserted()) { + if(this.scanner instanceof RecoveryScanner && ((RecoveryScanner)this.scanner).isInsertedToken()) { return this.scanner.startPosition; } return this.scanner.startPosition - 1; Index: model/org/eclipse/jdt/core/ICompilationUnit.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java,v retrieving revision 1.54 diff -u -r1.54 ICompilationUnit.java --- model/org/eclipse/jdt/core/ICompilationUnit.java 23 Jan 2006 10:08:24 -0000 1.54 +++ model/org/eclipse/jdt/core/ICompilationUnit.java 8 Feb 2006 11:49:30 -0000 @@ -512,6 +512,11 @@ * creation of the DOM AST was not requested, or if the requested level of AST * API is not supported, or if the working copy was already consistent. *

+ * + *

+ * The statement recovery is disable if this method is use. To recover statements with syntax + * errors {@link #reconcile(int, boolean, boolean, WorkingCopyOwner, IProgressMonitor)} must be use. + *

* * @param astLevel either {@link #NO_AST} if no AST is wanted, * or the {@linkplain AST#newAST(int) AST API level} of the AST if one is wanted Index: compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java,v retrieving revision 1.337 diff -u -r1.337 Parser.java --- compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java 6 Feb 2006 14:13:54 -0000 1.337 +++ compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java 8 Feb 2006 11:49:24 -0000 @@ -2654,11 +2654,32 @@ } protected void consumeEmptyStatement() { // EmptyStatement ::= ';' - if (this.scanner.source[this.endStatementPosition] == ';') { + char[] source = this.scanner.source; + if (source[this.endStatementPosition] == ';') { pushOnAstStack(new EmptyStatement(this.endStatementPosition, this.endStatementPosition)); } else { - // we have a Unicode for the ';' (/u003B) - pushOnAstStack(new EmptyStatement(this.endStatementPosition - 5, this.endStatementPosition)); + if(source.length > 5) { + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + int pos = this.endStatementPosition - 4; + while (source[pos] == 'u') { + pos--; + } + if (source[pos] == '\\' && + !((c1 = Character.getNumericValue(source[this.endStatementPosition - 3])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[this.endStatementPosition - 2])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[this.endStatementPosition - 1])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[this.endStatementPosition])) > 15 + || c4 < 0) && + ((char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4)) == ';'){ + // we have a Unicode for the ';' (/u003B) + pushOnAstStack(new EmptyStatement(pos, this.endStatementPosition)); + return; + } + } + pushOnAstStack(new EmptyStatement(this.endStatementPosition, this.endStatementPosition)); } } protected void consumeEmptySwitchBlock() { Index: compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java,v retrieving revision 1.4 diff -u -r1.4 RecoveryScanner.java --- compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java 20 Jan 2006 14:07:16 -0000 1.4 +++ compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java 8 Feb 2006 11:49:24 -0000 @@ -21,6 +21,7 @@ private int pendingTokensPtr = -1; private char[] fakeTokenSource = null; private boolean isInserted = true; + private boolean precededByRemoved = false; private int skipNextInsertedTokens = -1; public boolean record = true; @@ -120,6 +121,7 @@ } this.fakeTokenSource = null; + this.precededByRemoved = false; if(this.data.insertedTokens != null) { for (int i = 0; i <= this.data.insertedTokensPtr; i++) { @@ -128,6 +130,7 @@ this.pendingTokens = this.data.insertedTokens[i]; this.pendingTokensPtr = this.data.insertedTokens[i].length - 1; this.fakeTokenSource = CharOperation.NO_CHAR; + this.isInserted = true; this.startPosition = this.currentPosition - 1; this.skipNextInsertedTokens = i; return this.pendingTokens[this.pendingTokensPtr--]; @@ -148,6 +151,7 @@ this.pendingTokens = this.data.replacedTokens[i]; this.pendingTokensPtr = this.data.replacedTokens[i].length - 1; this.fakeTokenSource = CharOperation.NO_CHAR; + this.isInserted = false; this.currentPosition = this.data.replacedTokensEnd[i] + 1; return this.pendingTokens[this.pendingTokensPtr--]; } @@ -160,6 +164,7 @@ this.data.removedTokensEnd[i] >= this.currentPosition - 1) { this.data.removedTokenUsed[i] = true; this.currentPosition = this.data.removedTokensEnd[i] + 1; + this.precededByRemoved = false; return getNextToken(); } } @@ -190,14 +195,18 @@ return this.fakeTokenSource != null; } - public boolean isFakeTokenInserted() { + public boolean isInsertedToken() { return this.fakeTokenSource != null && this.isInserted; } - public boolean isFakeTokenReplaced() { + public boolean isReplacedToken() { return this.fakeTokenSource != null && !this.isInserted; } + public boolean isPrecededByRemovedToken() { + return this.precededByRemoved; + } + public void setData(RecoveryScannerData data) { if(data == null) { this.data = new RecoveryScannerData(); Index: compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObjectToIntArray.java =================================================================== RCS file: compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObjectToIntArray.java diff -N compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObjectToIntArray.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObjectToIntArray.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.util; + +/** + * Hashtable of {Object --> int[] } + */ +public final class HashtableOfObjectToIntArray implements Cloneable { + + // to avoid using Enumerations, walk the individual tables skipping nulls + public Object[] keyTable; + public int[][] valueTable; + + public int elementSize; // number of elements in the table + int threshold; + + public HashtableOfObjectToIntArray() { + this(13); + } + + public HashtableOfObjectToIntArray(int size) { + + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.keyTable = new Object[extraRoom]; + this.valueTable = new int[extraRoom][]; + } + + public Object clone() throws CloneNotSupportedException { + HashtableOfObjectToIntArray result = (HashtableOfObjectToIntArray) super.clone(); + result.elementSize = this.elementSize; + result.threshold = this.threshold; + + int length = this.keyTable.length; + result.keyTable = new Object[length]; + System.arraycopy(this.keyTable, 0, result.keyTable, 0, length); + + length = this.valueTable.length; + result.valueTable = new int[length][]; + System.arraycopy(this.valueTable, 0, result.valueTable, 0, length); + return result; + } + + public boolean containsKey(Object key) { + + int index = (key.hashCode()& 0x7FFFFFFF) % this.valueTable.length; + Object currentKey; + while ((currentKey = this.keyTable[index]) != null) { + if (currentKey.equals(key)) + return true; + index = (index + 1) % this.keyTable.length; + } + return false; + } + + public int[] get(Object key) { + + int index = (key.hashCode()& 0x7FFFFFFF) % this.valueTable.length; + Object currentKey; + while ((currentKey = this.keyTable[index]) != null) { + if (currentKey.equals(key)) + return this.valueTable[index]; + index = (index + 1) % this.keyTable.length; + } + return null; + } + + public void keysToArray(Object[] array) { + int index = 0; + for (int i=0, length=this.keyTable.length; i threshold) + rehash(); + return value; + } + + public int[] removeKey(Object key) { + + int index = (key.hashCode()& 0x7FFFFFFF) % this.valueTable.length; + Object currentKey; + while ((currentKey = this.keyTable[index]) != null) { + if (currentKey.equals(key)) { + int[] value = this.valueTable[index]; + elementSize--; + this.keyTable[index] = null; + rehash(); + return value; + } + index = (index + 1) % this.keyTable.length; + } + return null; + } + + private void rehash() { + + HashtableOfObjectToIntArray newHashtable = new HashtableOfObjectToIntArray(elementSize * 2); // double the number of expected elements + Object currentKey; + for (int i = this.keyTable.length; --i >= 0;) + if ((currentKey = this.keyTable[i]) != null) + newHashtable.put(currentKey, this.valueTable[i]); + + this.keyTable = newHashtable.keyTable; + this.valueTable = newHashtable.valueTable; + this.threshold = newHashtable.threshold; + } + + public int size() { + return elementSize; + } + + public String toString() { + String s = ""; //$NON-NLS-1$ + Object key; + for (int i = 0, length = this.keyTable.length; i < length; i++) + if ((key = this.keyTable[i]) != null) + s += key + " -> " + this.valueTable[i] + "\n"; //$NON-NLS-2$ //$NON-NLS-1$ + return s; + } +} #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java,v retrieving revision 1.5 diff -u -r1.5 ASTConverterRecoveryTest.java --- src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java 6 Feb 2006 14:14:23 -0000 1.5 +++ src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java 8 Feb 2006 11:49:34 -0000 @@ -21,8 +21,10 @@ import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.EmptyStatement; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; @@ -32,6 +34,7 @@ import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; public class ASTConverterRecoveryTest extends ConverterTestSetup { public ASTConverterRecoveryTest(String name) { @@ -352,4 +355,369 @@ checkSourceRange(simpleName, ",", source); //$NON-NLS-1$ } + + // check RECOVERED flag (insert tokens) + public void test0006() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " bar()\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " bar();\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) == 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not an expression statement", statement.getNodeType() == ASTNode.EXPRESSION_STATEMENT); //$NON-NLS-1$ + ExpressionStatement expressionStatement = (ExpressionStatement) statement; + checkSourceRange(expressionStatement, "bar()", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (expressionStatement.getFlags() & ASTNode.RECOVERED) != 0); + Expression expression = expressionStatement.getExpression(); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation = (MethodInvocation)expression; + checkSourceRange(methodInvocation, "bar()", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation.getFlags() & ASTNode.RECOVERED) == 0); + } + + // check RECOVERED flag (insert tokens) + public void test0007() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " bar(baz()\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " bar(baz());\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) == 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not an expression statement", statement.getNodeType() == ASTNode.EXPRESSION_STATEMENT); //$NON-NLS-1$ + ExpressionStatement expressionStatement = (ExpressionStatement) statement; + checkSourceRange(expressionStatement, "bar(baz()", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (expressionStatement.getFlags() & ASTNode.RECOVERED) != 0); + Expression expression = expressionStatement.getExpression(); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation = (MethodInvocation)expression; + checkSourceRange(methodInvocation, "bar(baz()", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (methodInvocation.getFlags() & ASTNode.RECOVERED) != 0); + List arguments = methodInvocation.arguments(); + assertEquals("wrong size", 1, arguments.size()); //$NON-NLS-1$ + Expression argument = (Expression) arguments.get(0); + assertTrue("Not a method invocation", argument.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation2 = (MethodInvocation) argument; + checkSourceRange(methodInvocation2, "baz()", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation2.getFlags() & ASTNode.RECOVERED) == 0); + } + + // check RECOVERED flag (insert tokens) + public void test0008() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " for(int i\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " for (int i; ; ) ;\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Not flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) != 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not a for statement", statement.getNodeType() == ASTNode.FOR_STATEMENT); //$NON-NLS-1$ + ForStatement forStatement = (ForStatement) statement; + checkSourceRange(forStatement, "for(int i", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (forStatement.getFlags() & ASTNode.RECOVERED) != 0); + List initializers = forStatement.initializers(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Expression expression = (Expression)initializers.get(0); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION); //$NON-NLS-1$ + VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression)expression; + checkSourceRange(variableDeclarationExpression, "int i", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (variableDeclarationExpression.getFlags() & ASTNode.RECOVERED) != 0); + List fragments = variableDeclarationExpression.fragments(); + assertEquals("wrong size", 1, fragments.size()); //$NON-NLS-1$ + VariableDeclarationFragment fragment = (VariableDeclarationFragment)fragments.get(0); + checkSourceRange(fragment, "i", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (fragment.getFlags() & ASTNode.RECOVERED) != 0); + SimpleName name = fragment.getName(); + checkSourceRange(name, "i", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (name.getFlags() & ASTNode.RECOVERED) == 0); + Statement statement2 = forStatement.getBody(); + assertTrue("Not an empty statement", statement2.getNodeType() == ASTNode.EMPTY_STATEMENT); //$NON-NLS-1$ + EmptyStatement emptyStatement = (EmptyStatement)statement2; + checkSourceRange(emptyStatement, "i", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (emptyStatement.getFlags() & ASTNode.RECOVERED) != 0); + } + + // check RECOVERED flag (remove tokens) + public void test0009() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " bar(baz());#\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " bar(baz());\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Not flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) != 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not an expression statement", statement.getNodeType() == ASTNode.EXPRESSION_STATEMENT); //$NON-NLS-1$ + ExpressionStatement expressionStatement = (ExpressionStatement) statement; + checkSourceRange(expressionStatement, "bar(baz());", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (expressionStatement.getFlags() & ASTNode.RECOVERED) == 0); + Expression expression = expressionStatement.getExpression(); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation = (MethodInvocation)expression; + checkSourceRange(methodInvocation, "bar(baz())", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation.getFlags() & ASTNode.RECOVERED) == 0); + List arguments = methodInvocation.arguments(); + assertEquals("wrong size", 1, arguments.size()); //$NON-NLS-1$ + Expression argument = (Expression) arguments.get(0); + assertTrue("Not a method invocation", argument.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation2 = (MethodInvocation) argument; + checkSourceRange(methodInvocation2, "baz()", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation2.getFlags() & ASTNode.RECOVERED) == 0); + } + + // check RECOVERED flag (remove tokens) + public void test0010() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " bar(baz())#;\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " bar(baz());\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) == 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not an expression statement", statement.getNodeType() == ASTNode.EXPRESSION_STATEMENT); //$NON-NLS-1$ + ExpressionStatement expressionStatement = (ExpressionStatement) statement; + checkSourceRange(expressionStatement, "bar(baz())#;", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (expressionStatement.getFlags() & ASTNode.RECOVERED) != 0); + Expression expression = expressionStatement.getExpression(); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation = (MethodInvocation)expression; + checkSourceRange(methodInvocation, "bar(baz())", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation.getFlags() & ASTNode.RECOVERED) == 0); + List arguments = methodInvocation.arguments(); + assertEquals("wrong size", 1, arguments.size()); //$NON-NLS-1$ + Expression argument = (Expression) arguments.get(0); + assertTrue("Not a method invocation", argument.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation2 = (MethodInvocation) argument; + checkSourceRange(methodInvocation2, "baz()", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation2.getFlags() & ASTNode.RECOVERED) == 0); + } + + // check RECOVERED flag (remove tokens) + public void test0011() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " bar(baz()#);\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " bar(baz());\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) == 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not an expression statement", statement.getNodeType() == ASTNode.EXPRESSION_STATEMENT); //$NON-NLS-1$ + ExpressionStatement expressionStatement = (ExpressionStatement) statement; + checkSourceRange(expressionStatement, "bar(baz()#);", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (expressionStatement.getFlags() & ASTNode.RECOVERED) == 0); + Expression expression = expressionStatement.getExpression(); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation = (MethodInvocation)expression; + checkSourceRange(methodInvocation, "bar(baz()#)", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (methodInvocation.getFlags() & ASTNode.RECOVERED) != 0); + List arguments = methodInvocation.arguments(); + assertEquals("wrong size", 1, arguments.size()); //$NON-NLS-1$ + Expression argument = (Expression) arguments.get(0); + assertTrue("Not a method invocation", argument.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation2 = (MethodInvocation) argument; + checkSourceRange(methodInvocation2, "baz()", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation2.getFlags() & ASTNode.RECOVERED) == 0); + } + + // check RECOVERED flag (insert tokens) + public void test0012() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter/src/test/X.java", + "package test;\n"+ + "\n"+ + "public class X {\n"+ + " void foo() {\n"+ + " bar()#\n"+ + " }\n"+ + "}\n"); + + char[] source = this.workingCopies[0].getSource().toCharArray(); + ASTNode result = runConversion(AST.JLS3, this.workingCopies[0], true, true); + + assertASTNodeEquals( + "package test;\n" + + "public class X {\n" + + " void foo(){\n" + + " bar();\n" + + " }\n" + + "}\n", + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue("Flag as RECOVERED", (methodDeclaration.getFlags() & ASTNode.RECOVERED) == 0); + Block block = methodDeclaration.getBody(); + assertTrue("Flag as RECOVERED", (block.getFlags() & ASTNode.RECOVERED) == 0); + List statements = block.statements(); + assertEquals("wrong size", 1, statements.size()); //$NON-NLS-1$ + Statement statement = (Statement) statements.get(0); + assertTrue("Not an expression statement", statement.getNodeType() == ASTNode.EXPRESSION_STATEMENT); //$NON-NLS-1$ + ExpressionStatement expressionStatement = (ExpressionStatement) statement; + checkSourceRange(expressionStatement, "bar()#", source); //$NON-NLS-1$ + assertTrue("Not flag as RECOVERED", (expressionStatement.getFlags() & ASTNode.RECOVERED) != 0); + Expression expression = expressionStatement.getExpression(); + assertTrue("Not a method invocation", expression.getNodeType() == ASTNode.METHOD_INVOCATION); //$NON-NLS-1$ + MethodInvocation methodInvocation = (MethodInvocation)expression; + checkSourceRange(methodInvocation, "bar()", source); //$NON-NLS-1$ + assertTrue("Flag as RECOVERED", (methodInvocation.getFlags() & ASTNode.RECOVERED) == 0); + } }