KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > core > dom > ASTRecoveryPropagator


1 /*******************************************************************************
2  * Copyright (c) 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.core.dom;
13
14 import java.util.List JavaDoc;
15 import java.util.Vector JavaDoc;
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 /**
26  * Internal AST visitor for propagating syntax errors.
27  */

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 JavaDoc stack = new Vector JavaDoc();
90     
91     ASTRecoveryPropagator(CategorizedProblem[] problems, RecoveryScannerData data) {
92         // visit Javadoc.tags() as well
93
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             // continue to visit the node only if it contains tokens modifications
147

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         // is inside diet part of the ast
185
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 JavaDoc();
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                     // unparent the expression to add it in the expression stateemnt
354
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 JavaDoc 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