removed unused private methods.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / ASTRecoveryPropagator.java
1 /*******************************************************************************
2  * Copyright (c) 2006, 2008 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 net.sourceforge.phpdt.core.dom;
13
14 import java.util.List;
15 import java.util.Vector;
16
17 import org.eclipse.jdt.core.compiler.CategorizedProblem;
18 import net.sourceforge.phpdt.core.compiler.CharOperation;
19 import net.sourceforge.phpdt.core.compiler.IProblem;
20 import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner;
21 import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData;
22 import net.sourceforge.phpdt.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 stack = new Vector();
90         
91         /**
92          * @noreference This method is not intended to be referenced by clients.
93          */
94         ASTRecoveryPropagator(CategorizedProblem[] problems, RecoveryScannerData data) {
95                 // visit Javadoc.tags() as well
96                 this.problems = problems;
97                 this.usedOrIrrelevantProblems = new boolean[problems.length];
98                 
99                 this.data = data;
100                 
101                 if(this.data != null) {
102                         
103                         int length = 0;
104                         for (int i = 0; i < data.insertedTokensPtr + 1; i++) {
105                                 length += data.insertedTokens[i].length;
106                         }
107                         this.insertedTokensKind = new int[length];
108                         this.insertedTokensPosition = new int[length];
109                         this.insertedTokensFlagged = new boolean[length];
110                         int tokenCount = 0;
111                         for (int i = 0; i < data.insertedTokensPtr + 1; i++) {
112                                 for (int j = 0; j < data.insertedTokens[i].length; j++) {
113                                         this.insertedTokensKind[tokenCount] = data.insertedTokens[i][j];
114                                         this.insertedTokensPosition[tokenCount] = data.insertedTokensPosition[i];
115                                         tokenCount++;
116                                 }
117                         }
118                         
119                         if(data.removedTokensPtr != -1) {
120                                 this.removedTokensFlagged = new boolean[data.removedTokensPtr + 1];
121                         }
122                         if(data.replacedTokensPtr != -1) {
123                                 this.replacedTokensFlagged = new boolean[data.replacedTokensPtr + 1];
124                         }
125                 }
126         }
127
128         public void endVisit(Block node) {
129                 this.blockDepth--;
130                 if(this.blockDepth <= 0) {
131                         flagNodeWithInsertedTokens();
132                 }
133                 super.endVisit(node);
134         }
135
136         
137
138         public boolean visit(Block node) {
139                 boolean visitChildren = super.visit(node);
140                 this.blockDepth++;
141                 return visitChildren;
142         }
143         
144         protected boolean visitNode(ASTNode node) {
145                 if(this.blockDepth > 0) {
146                         int start = node.getStartPosition();
147                         int end = start + node.getLength() - 1;
148                         
149                         // continue to visit the node only if it contains tokens modifications
150                         
151                         if(this.insertedTokensFlagged != null) {
152                                 for (int i = 0; i < this.insertedTokensFlagged.length; i++) {
153                                         if(this.insertedTokensPosition[i] >= start &&
154                                                         this.insertedTokensPosition[i] <= end) {
155                                                 return true;
156                                         }
157                                 }
158                         }
159                         
160                         if(this.removedTokensFlagged != null) {
161                                 for (int i = 0; i <= this.data.removedTokensPtr; i++) {
162                                         if(this.data.removedTokensStart[i] >= start &&
163                                                         this.data.removedTokensEnd[i] <= end) {
164                                                 return true;
165                                         }
166                                 }
167                         }
168                         
169                         if(this.replacedTokensFlagged != null) {
170                                 for (int i = 0; i <= this.data.replacedTokensPtr; i++) {
171                                         if(this.data.replacedTokensStart[i] >= start &&
172                                                         this.data.replacedTokensEnd[i] <= end) {
173                                                 return true;
174                                         }
175                                 }
176                         }
177                         
178                         return false;
179                 }
180                 return true;
181         }
182
183         protected void endVisitNode(ASTNode node) {
184                 int start = node.getStartPosition();
185                 int end = start + node.getLength() - 1;
186                 
187                 // is inside diet part of the ast
188                 if(this.blockDepth < 1) {
189                         switch (node.getNodeType()) {
190                                 case ASTNode.ANNOTATION_TYPE_DECLARATION:
191                                 case ASTNode.COMPILATION_UNIT:
192                                 case ASTNode.ENUM_DECLARATION:
193                                 case ASTNode.FIELD_DECLARATION:
194                                 case ASTNode.IMPORT_DECLARATION:
195                                 case ASTNode.INITIALIZER:
196                                 case ASTNode.METHOD_DECLARATION:
197                                 case ASTNode.PACKAGE_DECLARATION:
198                                 case ASTNode.TYPE_DECLARATION:
199                                 case ASTNode.MARKER_ANNOTATION:
200                                 case ASTNode.NORMAL_ANNOTATION:
201                                 case ASTNode.SINGLE_MEMBER_ANNOTATION:
202                                 case ASTNode.BLOCK:
203                                         if(this.markIncludedProblems(start, end)) {
204                                                 node.setFlags(node.getFlags() | ASTNode.RECOVERED);
205                                         }
206                                         break;
207                         }
208                 } else {                        
209                         this.markIncludedProblems(start, end);
210                         
211                         if(this.insertedTokensFlagged != null) {
212                                 if(this.lastEnd != end) {
213                                         flagNodeWithInsertedTokens();
214                                 }
215                                 this.stack.add(node);
216                         }
217
218                         if(this.removedTokensFlagged != null) {
219                                 for (int i = 0; i <= this.data.removedTokensPtr; i++) {
220                                         if(!this.removedTokensFlagged[i] &&
221                                                         this.data.removedTokensStart[i] >= start &&
222                                                         this.data.removedTokensEnd[i] <= end) {
223                                                 node.setFlags(node.getFlags() | ASTNode.RECOVERED);
224                                                 this.removedTokensFlagged[i] = true;
225                                         }
226                                 }
227                         }
228                         
229                         if(this.replacedTokensFlagged != null) {
230                                 for (int i = 0; i <= this.data.replacedTokensPtr; i++) {
231                                         if(!this.replacedTokensFlagged[i] &&
232                                                         this.data.replacedTokensStart[i] >= start &&
233                                                         this.data.replacedTokensEnd[i] <= end) {
234                                                 node.setFlags(node.getFlags() | ASTNode.RECOVERED);
235                                                 this.replacedTokensFlagged[i] = true;
236                                         }
237                                 }
238                         }
239                 }
240                 this.lastEnd = end;
241         }
242         
243         private void flagNodeWithInsertedTokens() {
244                 if(this.insertedTokensKind != null && this.insertedTokensKind.length > 0) {
245                         int s = this.stack.size();
246                         for (int i = s - 1; i > -1; i--) {
247                                 flagNodesWithInsertedTokensAtEnd((ASTNode)this.stack.get(i));
248                         }
249                         for (int i = 0; i < s; i++) {
250                                 flagNodesWithInsertedTokensInside((ASTNode)this.stack.get(i));
251                         }
252                         this.stack = new Vector();
253                 }
254         }
255         
256         private boolean flagNodesWithInsertedTokensAtEnd(ASTNode node) {
257                 int[] expectedEndingToken = this.endingTokens.get(node.getClass());
258                 if (expectedEndingToken != null) {
259                         int start = node.getStartPosition();
260                         int end = start + node.getLength() - 1;
261                         
262                         boolean flagParent = false;
263                         done : for (int i = this.insertedTokensKind.length - 1; i > -1 ; i--) {
264                                 if(!this.insertedTokensFlagged[i] &&
265                                                 this.insertedTokensPosition[i] == end){
266                                         this.insertedTokensFlagged[i] = true;
267                                         for (int j = 0; j < expectedEndingToken.length; j++) {
268                                                 if(expectedEndingToken[j] == this.insertedTokensKind[i]) {
269                                                         node.setFlags(node.getFlags() | ASTNode.RECOVERED);
270                                                         break done;
271                                                 }
272                                         }
273                                         flagParent = true;
274                                 }
275                         }
276                         
277                         if(flagParent) {
278                                 ASTNode parent = node.getParent();
279                                 while (parent != null) {
280                                         parent.setFlags(node.getFlags() | ASTNode.RECOVERED);
281                                         if((parent.getStartPosition() + parent.getLength() - 1) != end) {
282                                                 parent = null;
283                                         } else {
284                                                 parent = parent.getParent();
285                                         }
286                                 }
287                         }
288                 }
289                 return true;
290         }
291         
292         private boolean flagNodesWithInsertedTokensInside(ASTNode node) {
293                 int start = node.getStartPosition();
294                 int end = start + node.getLength() - 1;
295                 for (int i = 0; i < this.insertedTokensKind.length; i++) {
296                         if(!this.insertedTokensFlagged[i] &&
297                                         start <= this.insertedTokensPosition[i] &&
298                                         this.insertedTokensPosition[i] < end){
299                                 node.setFlags(node.getFlags() | ASTNode.RECOVERED);
300                                 this.insertedTokensFlagged[i] = true;
301                         }
302                 }
303                 return true;
304         }
305         
306         private boolean markIncludedProblems(int start, int end) {
307                 boolean foundProblems = false;
308                 next: for (int i = 0, max = this.problems.length; i < max; i++) {
309                         CategorizedProblem problem = this.problems[i];
310                         
311                         if(this.usedOrIrrelevantProblems[i]) continue next;
312                         
313                         switch(problem.getID()) {
314                                 case IProblem.ParsingErrorOnKeywordNoSuggestion :
315                                 case IProblem.ParsingErrorOnKeyword :
316                                 case IProblem.ParsingError :
317                                 case IProblem.ParsingErrorNoSuggestion :
318                                 case IProblem.ParsingErrorInsertTokenBefore :
319                                 case IProblem.ParsingErrorInsertTokenAfter :
320                                 case IProblem.ParsingErrorDeleteToken :
321                                 case IProblem.ParsingErrorDeleteTokens :
322                                 case IProblem.ParsingErrorMergeTokens :
323                                 case IProblem.ParsingErrorInvalidToken :
324                                 case IProblem.ParsingErrorMisplacedConstruct :
325                                 case IProblem.ParsingErrorReplaceTokens :
326                                 case IProblem.ParsingErrorNoSuggestionForTokens :
327                                 case IProblem.ParsingErrorUnexpectedEOF :
328                                 case IProblem.ParsingErrorInsertToComplete :
329                                 case IProblem.ParsingErrorInsertToCompleteScope :
330                                 case IProblem.ParsingErrorInsertToCompletePhrase :
331                                 case IProblem.EndOfSource :
332                                 case IProblem.InvalidHexa :
333                                 case IProblem.InvalidOctal :
334                                 case IProblem.InvalidCharacterConstant :
335                                 case IProblem.InvalidEscape :
336                                 case IProblem.InvalidInput :
337                                 case IProblem.InvalidUnicodeEscape :
338                                 case IProblem.InvalidFloat :
339                                 case IProblem.NullSourceString :
340                                 case IProblem.UnterminatedString :
341                                 case IProblem.UnterminatedComment :
342                                 case IProblem.InvalidDigit :
343                                         break;
344                                 default:
345                                         this.usedOrIrrelevantProblems[i] = true;
346                                         continue next;
347                                         
348                         }
349                         
350                         int problemStart = problem.getSourceStart();
351                         int problemEnd = problem.getSourceEnd();
352                         if ((start <= problemStart) && (problemStart <= end) ||
353                                         (start <= problemEnd) && (problemEnd <= end)) {
354                                 this.usedOrIrrelevantProblems[i] = true;
355                                 foundProblems = true;
356                         }
357                 }
358                 return foundProblems;
359         }
360
361         public void endVisit(ExpressionStatement node) {
362                 endVisitNode(node);
363                 if ((node.getFlags() & ASTNode.RECOVERED) == 0) return; 
364                 Expression expression = node.getExpression();
365                 if (expression.getNodeType() == ASTNode.ASSIGNMENT) {
366                         Assignment assignment = (Assignment) expression;
367                         Expression rightHandSide = assignment.getRightHandSide();
368                         if (rightHandSide.getNodeType() == ASTNode.SIMPLE_NAME) {
369                                 SimpleName simpleName = (SimpleName) rightHandSide;
370                                 if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) {
371                                         Expression expression2 =  assignment.getLeftHandSide();
372                                         // unparent the expression to add it in the expression stateemnt
373                                         expression2.setParent(null, null);
374                                         expression2.setFlags(expression2.getFlags() | ASTNode.RECOVERED);
375                                         node.setExpression(expression2);
376                                 }
377                         }
378                 }
379         }
380         
381         public void endVisit(ForStatement node) {
382                 endVisitNode(node);
383                 List initializers = node.initializers();
384                 if (initializers.size() == 1) {
385                         Expression expression = (Expression) initializers.get(0);
386                         if (expression.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
387                                 VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) expression;
388                                 List fragments = variableDeclarationExpression.fragments();
389                                 for (int i = 0, max = fragments.size(); i <max; i++) {
390                                         VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.get(i);
391                                         SimpleName simpleName = fragment.getName();
392                                         if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) {
393                                                 fragments.remove(fragment);
394                                                 variableDeclarationExpression.setFlags(variableDeclarationExpression.getFlags() | ASTNode.RECOVERED);
395                                         }
396                                 }
397                         }
398                 }
399         }
400
401         public void endVisit(VariableDeclarationStatement node) {
402                 endVisitNode(node);
403                 List fragments = node.fragments();
404                 for (int i = 0, max = fragments.size(); i <max; i++) {
405                         VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.get(i);
406                         Expression expression = fragment.getInitializer();
407                         if (expression == null) continue;
408                         if ((expression.getFlags() & ASTNode.RECOVERED) == 0) continue;
409                         if (expression.getNodeType() == ASTNode.SIMPLE_NAME) {
410                                 SimpleName simpleName = (SimpleName) expression;
411                                 if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) {
412                                         fragment.setInitializer(null);
413                                         fragment.setFlags(fragment.getFlags() | ASTNode.RECOVERED);
414                                 }
415                         }
416                 }
417         }
418         
419         public void endVisit(NormalAnnotation node) {
420                 endVisitNode(node);
421                 // is inside diet part of the ast
422                 if(this.blockDepth < 1) {
423                         List values = node.values();
424                         int size = values.size();
425                         if (size > 0) {
426                                 MemberValuePair lastMemberValuePair = (MemberValuePair)values.get(size - 1);
427                                 
428                                 int annotationEnd = node.getStartPosition() + node.getLength();
429                                 int lastMemberValuePairEnd = lastMemberValuePair.getStartPosition() + lastMemberValuePair.getLength();
430                                 if (annotationEnd == lastMemberValuePairEnd) {
431                                         node.setFlags(node.getFlags() | ASTNode.RECOVERED);
432                                 }
433                         }
434                 }
435         }
436         
437         public void endVisit(SingleMemberAnnotation node) {
438                 endVisitNode(node);
439                 // is inside diet part of the ast
440                 if(this.blockDepth < 1) {
441                         Expression value = node.getValue();
442                         int annotationEnd = node.getStartPosition() + node.getLength();
443                         int valueEnd = value.getStartPosition() + value.getLength();
444                         if (annotationEnd == valueEnd) {
445                                 node.setFlags(node.getFlags() | ASTNode.RECOVERED);
446                         }
447                 }
448         }
449 }