1 11 12 package org.eclipse.jdt.core.dom; 13 14 import java.util.List ; 15 import java.util.Vector ; 16 17 import org.eclipse.jdt.core.compiler.CategorizedProblem; 18 import org.eclipse.jdt.core.compiler.CharOperation; 19 import org.eclipse.jdt.core.compiler.IProblem; 20 import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; 21 import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; 22 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; 23 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToIntArray; 24 25 28 class ASTRecoveryPropagator extends DefaultASTVisitor { 29 private static final int NOTHING = -1; 30 HashtableOfObjectToIntArray endingTokens = new HashtableOfObjectToIntArray(); 31 { 32 this.endingTokens.put(AnonymousClassDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE}); 33 this.endingTokens.put(ArrayAccess.class, new int[]{TerminalTokens.TokenNameRBRACKET}); 34 this.endingTokens.put(ArrayCreation.class, new int[]{NOTHING, TerminalTokens.TokenNameRBRACKET}); 35 this.endingTokens.put(ArrayInitializer.class, new int[]{TerminalTokens.TokenNameRBRACE}); 36 this.endingTokens.put(ArrayType.class, new int[]{TerminalTokens.TokenNameRBRACKET}); 37 this.endingTokens.put(AssertStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 38 this.endingTokens.put(Block.class, new int[]{TerminalTokens.TokenNameRBRACE}); 39 this.endingTokens.put(BooleanLiteral.class, new int[]{TerminalTokens.TokenNamefalse, TerminalTokens.TokenNametrue}); 40 this.endingTokens.put(BreakStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 41 this.endingTokens.put(CharacterLiteral.class, new int[]{TerminalTokens.TokenNameCharacterLiteral}); 42 this.endingTokens.put(ClassInstanceCreation.class, new int[]{TerminalTokens.TokenNameRBRACE, TerminalTokens.TokenNameRPAREN}); 43 this.endingTokens.put(ConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 44 this.endingTokens.put(ContinueStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 45 this.endingTokens.put(DoStatement.class, new int[]{TerminalTokens.TokenNameRPAREN}); 46 this.endingTokens.put(EmptyStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 47 this.endingTokens.put(ExpressionStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 48 this.endingTokens.put(FieldDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 49 this.endingTokens.put(ImportDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 50 this.endingTokens.put(Initializer.class, new int[]{TerminalTokens.TokenNameRBRACE}); 51 this.endingTokens.put(MethodDeclaration.class, new int[]{NOTHING, TerminalTokens.TokenNameSEMICOLON}); 52 this.endingTokens.put(MethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN}); 53 this.endingTokens.put(NullLiteral.class, new int[]{TerminalTokens.TokenNamenull}); 54 this.endingTokens.put(NumberLiteral.class, new int[]{TerminalTokens.TokenNameIntegerLiteral, TerminalTokens.TokenNameLongLiteral, TerminalTokens.TokenNameFloatingPointLiteral, TerminalTokens.TokenNameDoubleLiteral}); 55 this.endingTokens.put(PackageDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 56 this.endingTokens.put(ParenthesizedExpression.class, new int[]{TerminalTokens.TokenNameRPAREN}); 57 this.endingTokens.put(PostfixExpression.class, new int[]{TerminalTokens.TokenNamePLUS_PLUS, TerminalTokens.TokenNameMINUS_MINUS}); 58 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}); 59 this.endingTokens.put(ReturnStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 60 this.endingTokens.put(SimpleName.class, new int[]{TerminalTokens.TokenNameIdentifier}); 61 this.endingTokens.put(SingleVariableDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 62 this.endingTokens.put(StringLiteral.class, new int[]{TerminalTokens.TokenNameStringLiteral}); 63 this.endingTokens.put(SuperConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 64 this.endingTokens.put(SuperMethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN}); 65 this.endingTokens.put(SwitchCase.class, new int[]{TerminalTokens.TokenNameCOLON}); 66 this.endingTokens.put(SwitchStatement.class, new int[]{TerminalTokens.TokenNameRBRACE}); 67 this.endingTokens.put(SynchronizedStatement.class, new int[]{TerminalTokens.TokenNameRBRACE}); 68 this.endingTokens.put(ThisExpression.class, new int[]{TerminalTokens.TokenNamethis}); 69 this.endingTokens.put(ThrowStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 70 this.endingTokens.put(TypeDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE}); 71 this.endingTokens.put(TypeLiteral.class, new int[]{TerminalTokens.TokenNameclass}); 72 this.endingTokens.put(VariableDeclarationStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); 73 } 74 75 private CategorizedProblem[] problems; 76 private boolean[] usedOrIrrelevantProblems; 77 78 private RecoveryScannerData data; 79 private int blockDepth = 0; 80 private int lastEnd; 81 82 private int[] insertedTokensKind; 83 private int[] insertedTokensPosition; 84 private boolean[] insertedTokensFlagged; 85 86 private boolean[] removedTokensFlagged; 87 private boolean[] replacedTokensFlagged; 88 89 private Vector stack = new Vector (); 90 91 ASTRecoveryPropagator(CategorizedProblem[] problems, RecoveryScannerData data) { 92 this.problems = problems; 94 this.usedOrIrrelevantProblems = new boolean[problems.length]; 95 96 this.data = data; 97 98 if(this.data != null) { 99 100 int length = 0; 101 for (int i = 0; i < data.insertedTokensPtr + 1; i++) { 102 length += data.insertedTokens[i].length; 103 } 104 this.insertedTokensKind = new int[length]; 105 this.insertedTokensPosition = new int[length]; 106 this.insertedTokensFlagged = new boolean[length]; 107 int tokenCount = 0; 108 for (int i = 0; i < data.insertedTokensPtr + 1; i++) { 109 for (int j = 0; j < data.insertedTokens[i].length; j++) { 110 this.insertedTokensKind[tokenCount] = data.insertedTokens[i][j]; 111 this.insertedTokensPosition[tokenCount] = data.insertedTokensPosition[i]; 112 tokenCount++; 113 } 114 } 115 116 if(data.removedTokensPtr != -1) { 117 this.removedTokensFlagged = new boolean[data.removedTokensPtr + 1]; 118 } 119 if(data.replacedTokensPtr != -1) { 120 this.replacedTokensFlagged = new boolean[data.replacedTokensPtr + 1]; 121 } 122 } 123 } 124 125 public void endVisit(Block node) { 126 this.blockDepth--; 127 if(this.blockDepth <= 0) { 128 flagNodeWithInsertedTokens(); 129 } 130 super.endVisit(node); 131 } 132 133 134 135 public boolean visit(Block node) { 136 boolean visitChildren = super.visit(node); 137 this.blockDepth++; 138 return visitChildren; 139 } 140 141 protected boolean visitNode(ASTNode node) { 142 if(this.blockDepth > 0) { 143 int start = node.getStartPosition(); 144 int end = start + node.getLength() - 1; 145 146 148 if(this.insertedTokensFlagged != null) { 149 for (int i = 0; i < this.insertedTokensFlagged.length; i++) { 150 if(this.insertedTokensPosition[i] >= start && 151 this.insertedTokensPosition[i] <= end) { 152 return true; 153 } 154 } 155 } 156 157 if(this.removedTokensFlagged != null) { 158 for (int i = 0; i <= this.data.removedTokensPtr; i++) { 159 if(this.data.removedTokensStart[i] >= start && 160 this.data.removedTokensEnd[i] <= end) { 161 return true; 162 } 163 } 164 } 165 166 if(this.replacedTokensFlagged != null) { 167 for (int i = 0; i <= this.data.replacedTokensPtr; i++) { 168 if(this.data.replacedTokensStart[i] >= start && 169 this.data.replacedTokensEnd[i] <= end) { 170 return true; 171 } 172 } 173 } 174 175 return false; 176 } 177 return true; 178 } 179 180 protected void endVisitNode(ASTNode node) { 181 int start = node.getStartPosition(); 182 int end = start + node.getLength() - 1; 183 184 if(this.blockDepth < 1) { 186 if(this.markIncludedProblems(start, end)) { 187 node.setFlags(node.getFlags() | ASTNode.RECOVERED); 188 } 189 } else { 190 this.markIncludedProblems(start, end); 191 192 if(this.insertedTokensFlagged != null) { 193 if(this.lastEnd != end) { 194 flagNodeWithInsertedTokens(); 195 } 196 this.stack.add(node); 197 } 198 199 if(this.removedTokensFlagged != null) { 200 for (int i = 0; i <= this.data.removedTokensPtr; i++) { 201 if(!this.removedTokensFlagged[i] && 202 this.data.removedTokensStart[i] >= start && 203 this.data.removedTokensEnd[i] <= end) { 204 node.setFlags(node.getFlags() | ASTNode.RECOVERED); 205 this.removedTokensFlagged[i] = true; 206 } 207 } 208 } 209 210 if(this.replacedTokensFlagged != null) { 211 for (int i = 0; i <= this.data.replacedTokensPtr; i++) { 212 if(!this.replacedTokensFlagged[i] && 213 this.data.replacedTokensStart[i] >= start && 214 this.data.replacedTokensEnd[i] <= end) { 215 node.setFlags(node.getFlags() | ASTNode.RECOVERED); 216 this.replacedTokensFlagged[i] = true; 217 } 218 } 219 } 220 } 221 this.lastEnd = end; 222 } 223 224 private void flagNodeWithInsertedTokens() { 225 if(this.insertedTokensKind != null && this.insertedTokensKind.length > 0) { 226 int s = this.stack.size(); 227 for (int i = s - 1; i > -1; i--) { 228 flagNodesWithInsertedTokensAtEnd((ASTNode)this.stack.get(i)); 229 } 230 for (int i = 0; i < s; i++) { 231 flagNodesWithInsertedTokensInside((ASTNode)this.stack.get(i)); 232 } 233 this.stack = new Vector (); 234 } 235 } 236 237 private boolean flagNodesWithInsertedTokensAtEnd(ASTNode node) { 238 int[] expectedEndingToken = this.endingTokens.get(node.getClass()); 239 if (expectedEndingToken != null) { 240 int start = node.getStartPosition(); 241 int end = start + node.getLength() - 1; 242 243 boolean flagParent = false; 244 done : for (int i = this.insertedTokensKind.length - 1; i > -1 ; i--) { 245 if(!this.insertedTokensFlagged[i] && 246 this.insertedTokensPosition[i] == end){ 247 this.insertedTokensFlagged[i] = true; 248 for (int j = 0; j < expectedEndingToken.length; j++) { 249 if(expectedEndingToken[j] == this.insertedTokensKind[i]) { 250 node.setFlags(node.getFlags() | ASTNode.RECOVERED); 251 break done; 252 } 253 } 254 flagParent = true; 255 } 256 } 257 258 if(flagParent) { 259 ASTNode parent = node.getParent(); 260 while (parent != null) { 261 parent.setFlags(node.getFlags() | ASTNode.RECOVERED); 262 if((parent.getStartPosition() + parent.getLength() - 1) != end) { 263 parent = null; 264 } else { 265 parent = parent.getParent(); 266 } 267 } 268 } 269 } 270 return true; 271 } 272 273 private boolean flagNodesWithInsertedTokensInside(ASTNode node) { 274 int start = node.getStartPosition(); 275 int end = start + node.getLength() - 1; 276 for (int i = 0; i < this.insertedTokensKind.length; i++) { 277 if(!this.insertedTokensFlagged[i] && 278 start <= this.insertedTokensPosition[i] && 279 this.insertedTokensPosition[i] < end){ 280 node.setFlags(node.getFlags() | ASTNode.RECOVERED); 281 this.insertedTokensFlagged[i] = true; 282 } 283 } 284 return true; 285 } 286 287 private boolean markIncludedProblems(int start, int end) { 288 boolean foundProblems = false; 289 next: for (int i = 0, max = this.problems.length; i < max; i++) { 290 CategorizedProblem problem = this.problems[i]; 291 292 if(this.usedOrIrrelevantProblems[i]) continue next; 293 294 switch(problem.getID()) { 295 case IProblem.ParsingErrorOnKeywordNoSuggestion : 296 case IProblem.ParsingErrorOnKeyword : 297 case IProblem.ParsingError : 298 case IProblem.ParsingErrorNoSuggestion : 299 case IProblem.ParsingErrorInsertTokenBefore : 300 case IProblem.ParsingErrorInsertTokenAfter : 301 case IProblem.ParsingErrorDeleteToken : 302 case IProblem.ParsingErrorDeleteTokens : 303 case IProblem.ParsingErrorMergeTokens : 304 case IProblem.ParsingErrorInvalidToken : 305 case IProblem.ParsingErrorMisplacedConstruct : 306 case IProblem.ParsingErrorReplaceTokens : 307 case IProblem.ParsingErrorNoSuggestionForTokens : 308 case IProblem.ParsingErrorUnexpectedEOF : 309 case IProblem.ParsingErrorInsertToComplete : 310 case IProblem.ParsingErrorInsertToCompleteScope : 311 case IProblem.ParsingErrorInsertToCompletePhrase : 312 case IProblem.EndOfSource : 313 case IProblem.InvalidHexa : 314 case IProblem.InvalidOctal : 315 case IProblem.InvalidCharacterConstant : 316 case IProblem.InvalidEscape : 317 case IProblem.InvalidInput : 318 case IProblem.InvalidUnicodeEscape : 319 case IProblem.InvalidFloat : 320 case IProblem.NullSourceString : 321 case IProblem.UnterminatedString : 322 case IProblem.UnterminatedComment : 323 case IProblem.InvalidDigit : 324 break; 325 default: 326 this.usedOrIrrelevantProblems[i] = true; 327 continue next; 328 329 } 330 331 int problemStart = problem.getSourceStart(); 332 int problemEnd = problem.getSourceEnd(); 333 if ((start <= problemStart) && (problemStart <= end) || 334 (start <= problemEnd) && (problemEnd <= end)) { 335 this.usedOrIrrelevantProblems[i] = true; 336 foundProblems = true; 337 } 338 } 339 return foundProblems; 340 } 341 342 public void endVisit(ExpressionStatement node) { 343 endVisitNode(node); 344 if ((node.getFlags() & ASTNode.RECOVERED) == 0) return; 345 Expression expression = node.getExpression(); 346 if (expression.getNodeType() == ASTNode.ASSIGNMENT) { 347 Assignment assignment = (Assignment) expression; 348 Expression rightHandSide = assignment.getRightHandSide(); 349 if (rightHandSide.getNodeType() == ASTNode.SIMPLE_NAME) { 350 SimpleName simpleName = (SimpleName) rightHandSide; 351 if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) { 352 Expression expression2 = assignment.getLeftHandSide(); 353 expression2.setParent(null, null); 355 expression2.setFlags(expression2.getFlags() | ASTNode.RECOVERED); 356 node.setExpression(expression2); 357 } 358 } 359 } 360 } 361 362 public void endVisit(VariableDeclarationStatement node) { 363 endVisitNode(node); 364 List fragments = node.fragments(); 365 for (int i = 0, max = fragments.size(); i <max; i++) { 366 VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.get(i); 367 Expression expression = fragment.getInitializer(); 368 if (expression == null) continue; 369 if ((expression.getFlags() & ASTNode.RECOVERED) == 0) continue; 370 if (expression.getNodeType() == ASTNode.SIMPLE_NAME) { 371 SimpleName simpleName = (SimpleName) expression; 372 if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) { 373 fragment.setInitializer(null); 374 fragment.setFlags(node.getFlags() | ASTNode.RECOVERED); 375 } 376 } 377 } 378 } 379 } 380 | Popular Tags |