EclipseJDT Source Viewer

Home|eclipse_jdt/src/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java
1/*******************************************************************************
2 * Copyright (c) 2006, 2020 IBM Corporation and others.
3 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
10 *
11 * Contributors:
12 *     IBM Corporation - initial API and implementation
13 *******************************************************************************/
14
15package org.eclipse.jdt.core.dom;
16
17import java.util.ArrayList;
18import java.util.List;
19
20import org.eclipse.jdt.core.compiler.CategorizedProblem;
21import org.eclipse.jdt.core.compiler.CharOperation;
22import org.eclipse.jdt.core.compiler.IProblem;
23import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner;
24import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData;
25import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
26import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToIntArray;
27
28/**
29 * Internal AST visitor for propagating syntax errors.
30 */
31@SuppressWarnings({"rawtypes"})
32class ASTRecoveryPropagator extends DefaultASTVisitor {
33    private static final int NOTHING = -1;
34    HashtableOfObjectToIntArray endingTokens = new HashtableOfObjectToIntArray();
35    {
36        this.endingTokens.put(AnonymousClassDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE});
37        this.endingTokens.put(ArrayAccess.class, new int[]{TerminalTokens.TokenNameRBRACKET});
38        this.endingTokens.put(ArrayCreation.class, new int[]{NOTHINGTerminalTokens.TokenNameRBRACKET});
39        this.endingTokens.put(ArrayInitializer.class, new int[]{TerminalTokens.TokenNameRBRACE});
40        this.endingTokens.put(ArrayType.class, new int[]{TerminalTokens.TokenNameRBRACKET});
41        this.endingTokens.put(AssertStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
42        this.endingTokens.put(Block.class, new int[]{TerminalTokens.TokenNameRBRACE});
43        this.endingTokens.put(BooleanLiteral.class, new int[]{TerminalTokens.TokenNamefalseTerminalTokens.TokenNametrue});
44        this.endingTokens.put(BreakStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
45        this.endingTokens.put(CharacterLiteral.class, new int[]{TerminalTokens.TokenNameCharacterLiteral});
46        this.endingTokens.put(ClassInstanceCreation.class, new int[]{TerminalTokens.TokenNameRBRACETerminalTokens.TokenNameRPAREN});
47        this.endingTokens.put(ConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
48        this.endingTokens.put(ContinueStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
49        this.endingTokens.put(DoStatement.class, new int[]{TerminalTokens.TokenNameRPAREN});
50        this.endingTokens.put(EmptyStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
51        this.endingTokens.put(ExpressionStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
52        this.endingTokens.put(FieldDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
53        this.endingTokens.put(ImportDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
54        this.endingTokens.put(Initializer.class, new int[]{TerminalTokens.TokenNameRBRACE});
55        this.endingTokens.put(MethodDeclaration.class, new int[]{NOTHINGTerminalTokens.TokenNameSEMICOLON});
56        this.endingTokens.put(MethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN});
57        this.endingTokens.put(ModuleDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE});
58        this.endingTokens.put(ModuleDirective.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
59        this.endingTokens.put(NullLiteral.class, new int[]{TerminalTokens.TokenNamenull});
60        this.endingTokens.put(NumberLiteral.class, new int[]{TerminalTokens.TokenNameIntegerLiteralTerminalTokens.TokenNameLongLiteralTerminalTokens.TokenNameFloatingPointLiteralTerminalTokens.TokenNameDoubleLiteral});
61        this.endingTokens.put(PackageDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
62        this.endingTokens.put(ParenthesizedExpression.class, new int[]{TerminalTokens.TokenNameRPAREN});
63        this.endingTokens.put(PostfixExpression.class, new int[]{TerminalTokens.TokenNamePLUS_PLUSTerminalTokens.TokenNameMINUS_MINUS});
64        this.endingTokens.put(PrimitiveType.class, new int[]{TerminalTokens.TokenNamebyteTerminalTokens.TokenNameshortTerminalTokens.TokenNamecharTerminalTokens.TokenNameintTerminalTokens.TokenNamelongTerminalTokens.TokenNamefloatTerminalTokens.TokenNamebooleanTerminalTokens.TokenNamedoubleTerminalTokens.TokenNamevoid});
65        this.endingTokens.put(ReturnStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
66        this.endingTokens.put(SimpleName.class, new int[]{TerminalTokens.TokenNameIdentifier});
67        this.endingTokens.put(SingleVariableDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
68        this.endingTokens.put(StringLiteral.class, new int[]{TerminalTokens.TokenNameStringLiteral});
69        this.endingTokens.put(SuperConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
70        this.endingTokens.put(SuperMethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN});
71        this.endingTokens.put(SwitchCase.class, new int[]{TerminalTokens.TokenNameCOLON});
72        this.endingTokens.put(SwitchStatement.class, new int[]{TerminalTokens.TokenNameRBRACE});
73        this.endingTokens.put(SynchronizedStatement.class, new int[]{TerminalTokens.TokenNameRBRACE});
74        this.endingTokens.put(ThisExpression.class, new int[]{TerminalTokens.TokenNamethis});
75        this.endingTokens.put(ThrowStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
76        this.endingTokens.put(TypeDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE});
77        this.endingTokens.put(TypeLiteral.class, new int[]{TerminalTokens.TokenNameclass});
78        this.endingTokens.put(VariableDeclarationStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON});
79    }
80
81    private CategorizedProblem[] problems;
82    private boolean[] usedOrIrrelevantProblems;
83
84    private RecoveryScannerData data;
85    private int blockDepth = 0;
86    private int lastEnd;
87
88    private int[] insertedTokensKind;
89    private int[] insertedTokensPosition;
90    private boolean[] insertedTokensFlagged;
91
92    private boolean[] removedTokensFlagged;
93    private boolean[] replacedTokensFlagged;
94
95    private ArrayList<ASTNodestack = new ArrayList<>();
96
97    ASTRecoveryPropagator(CategorizedProblem[] problemsRecoveryScannerData data) {
98        // visit Javadoc.tags() as well
99        this.problems = problems;
100        this.usedOrIrrelevantProblems = new boolean[problems.length];
101
102        this.data = data;
103
104        if(this.data != null) {
105
106            int length = 0;
107            for (int i = 0i < data.insertedTokensPtr + 1i++) {
108                length += data.insertedTokens[i].length;
109            }
110            this.insertedTokensKind = new int[length];
111            this.insertedTokensPosition = new int[length];
112            this.insertedTokensFlagged = new boolean[length];
113            int tokenCount = 0;
114            for (int i = 0i < data.insertedTokensPtr + 1i++) {
115                for (int j = 0j < data.insertedTokens[i].lengthj++) {
116                    this.insertedTokensKind[tokenCount] = data.insertedTokens[i][j];
117                    this.insertedTokensPosition[tokenCount] = data.insertedTokensPosition[i];
118                    tokenCount++;
119                }
120            }
121
122            if(data.removedTokensPtr != -1) {
123                this.removedTokensFlagged = new boolean[data.removedTokensPtr + 1];
124            }
125            if(data.replacedTokensPtr != -1) {
126                this.replacedTokensFlagged = new boolean[data.replacedTokensPtr + 1];
127            }
128        }
129    }
130
131    @Override
132    public void endVisit(Block node) {
133        this.blockDepth--;
134        if(this.blockDepth <= 0) {
135            flagNodeWithInsertedTokens();
136        }
137        super.endVisit(node);
138    }
139
140
141
142    @Override
143    public boolean visit(Block node) {
144        boolean visitChildren = super.visit(node);
145        this.blockDepth++;
146        return visitChildren;
147    }
148
149    @Override
150    protected boolean visitNode(ASTNode node) {
151        if(this.blockDepth > 0) {
152            int start = node.getStartPosition();
153            int end = start + node.getLength() - 1;
154
155            // continue to visit the node only if it contains tokens modifications
156
157            if(this.insertedTokensFlagged != null) {
158                for (int i = 0i < this.insertedTokensFlagged.lengthi++) {
159                    if(this.insertedTokensPosition[i] >= start &&
160                            this.insertedTokensPosition[i] <= end) {
161                        return true;
162                    }
163                }
164            }
165
166            if(this.removedTokensFlagged != null) {
167                for (int i = 0i <= this.data.removedTokensPtri++) {
168                    if(this.data.removedTokensStart[i] >= start &&
169                            this.data.removedTokensEnd[i] <= end) {
170                        return true;
171                    }
172                }
173            }
174
175            if(this.replacedTokensFlagged != null) {
176                for (int i = 0i <= this.data.replacedTokensPtri++) {
177                    if(this.data.replacedTokensStart[i] >= start &&
178                            this.data.replacedTokensEnd[i] <= end) {
179                        return true;
180                    }
181                }
182            }
183
184            return false;
185        }
186        return true;
187    }
188
189    @Override
190    protected void endVisitNode(ASTNode node) {
191        int start = node.getStartPosition();
192        int end = start + node.getLength() - 1;
193
194        // is inside diet part of the ast
195        if(this.blockDepth < 1) {
196            switch (node.getNodeType()) {
197                case ASTNode.ANNOTATION_TYPE_DECLARATION:
198                case ASTNode.COMPILATION_UNIT:
199                case ASTNode.ENUM_DECLARATION:
200                case ASTNode.FIELD_DECLARATION:
201                case ASTNode.IMPORT_DECLARATION:
202                case ASTNode.INITIALIZER:
203                case ASTNode.METHOD_DECLARATION:
204                case ASTNode.MODULE_DECLARATION:
205                case ASTNode.PACKAGE_DECLARATION:
206                case ASTNode.TYPE_DECLARATION:
207                case ASTNode.MARKER_ANNOTATION:
208                case ASTNode.NORMAL_ANNOTATION:
209                case ASTNode.SINGLE_MEMBER_ANNOTATION:
210                case ASTNode.BLOCK:
211                    if(markIncludedProblems(startend)) {
212                        node.setFlags(node.getFlags() | ASTNode.RECOVERED);
213                    }
214                    break;
215            }
216        } else {
217            markIncludedProblems(startend);
218
219            if(this.insertedTokensFlagged != null) {
220                if(this.lastEnd != end) {
221                    flagNodeWithInsertedTokens();
222                }
223                this.stack.add(node);
224            }
225
226            if(this.removedTokensFlagged != null) {
227                for (int i = 0i <= this.data.removedTokensPtri++) {
228                    if(!this.removedTokensFlagged[i] &&
229                            this.data.removedTokensStart[i] >= start &&
230                            this.data.removedTokensEnd[i] <= end) {
231                        node.setFlags(node.getFlags() | ASTNode.RECOVERED);
232                        this.removedTokensFlagged[i] = true;
233                    }
234                }
235            }
236
237            if(this.replacedTokensFlagged != null) {
238                for (int i = 0i <= this.data.replacedTokensPtri++) {
239                    if(!this.replacedTokensFlagged[i] &&
240                            this.data.replacedTokensStart[i] >= start &&
241                            this.data.replacedTokensEnd[i] <= end) {
242                        node.setFlags(node.getFlags() | ASTNode.RECOVERED);
243                        this.replacedTokensFlagged[i] = true;
244                    }
245                }
246            }
247        }
248        this.lastEnd = end;
249    }
250
251    private void flagNodeWithInsertedTokens() {
252        if(this.insertedTokensKind != null && this.insertedTokensKind.length > 0) {
253            int s = this.stack.size();
254            for (int i = s - 1i > -1i--) {
255                flagNodesWithInsertedTokensAtEnd(this.stack.get(i));
256            }
257            for (int i = 0i < si++) {
258                flagNodesWithInsertedTokensInside(this.stack.get(i));
259            }
260            this.stack = new ArrayList<>();
261        }
262    }
263
264    private boolean flagNodesWithInsertedTokensAtEnd(ASTNode node) {
265        int[] expectedEndingToken = this.endingTokens.get(node.getClass());
266        if (expectedEndingToken != null) {
267            int start = node.getStartPosition();
268            int end = start + node.getLength() - 1;
269
270            boolean flagParent = false;
271            done : for (int i = this.insertedTokensKind.length - 1i > -1 ; i--) {
272                if(!this.insertedTokensFlagged[i] &&
273                        this.insertedTokensPosition[i] == end){
274                    this.insertedTokensFlagged[i] = true;
275                    for (int j = 0j < expectedEndingToken.lengthj++) {
276                        if(expectedEndingToken[j] == this.insertedTokensKind[i]) {
277                            node.setFlags(node.getFlags() | ASTNode.RECOVERED);
278                            break done;
279                        }
280                    }
281                    flagParent = true;
282                }
283            }
284
285            if(flagParent) {
286                ASTNode parent = node.getParent();
287                while (parent != null) {
288                    parent.setFlags(node.getFlags() | ASTNode.RECOVERED);
289                    if((parent.getStartPosition() + parent.getLength() - 1) != end) {
290                        parent = null;
291                    } else {
292                        parent = parent.getParent();
293                    }
294                }
295            }
296        }
297        return true;
298    }
299
300    private boolean flagNodesWithInsertedTokensInside(ASTNode node) {
301        int start = node.getStartPosition();
302        int end = start + node.getLength() - 1;
303        for (int i = 0i < this.insertedTokensKind.lengthi++) {
304            if(!this.insertedTokensFlagged[i] &&
305                    start <= this.insertedTokensPosition[i] &&
306                    this.insertedTokensPosition[i] < end){
307                node.setFlags(node.getFlags() | ASTNode.RECOVERED);
308                this.insertedTokensFlagged[i] = true;
309            }
310        }
311        return true;
312    }
313
314    private boolean markIncludedProblems(int startint end) {
315        boolean foundProblems = false;
316        next: for (int i = 0max = this.problems.lengthi < maxi++) {
317            CategorizedProblem problem = this.problems[i];
318
319            if(this.usedOrIrrelevantProblems[i]) continue next;
320
321            switch(problem.getID()) {
322                case IProblem.ParsingErrorOnKeywordNoSuggestion :
323                case IProblem.ParsingErrorOnKeyword :
324                case IProblem.ParsingError :
325                case IProblem.ParsingErrorNoSuggestion :
326                case IProblem.ParsingErrorInsertTokenBefore :
327                case IProblem.ParsingErrorInsertTokenAfter :
328                case IProblem.ParsingErrorDeleteToken :
329                case IProblem.ParsingErrorDeleteTokens :
330                case IProblem.ParsingErrorMergeTokens :
331                case IProblem.ParsingErrorInvalidToken :
332                case IProblem.ParsingErrorMisplacedConstruct :
333                case IProblem.ParsingErrorReplaceTokens :
334                case IProblem.ParsingErrorNoSuggestionForTokens :
335                case IProblem.ParsingErrorUnexpectedEOF :
336                case IProblem.ParsingErrorInsertToComplete :
337                case IProblem.ParsingErrorInsertToCompleteScope :
338                case IProblem.ParsingErrorInsertToCompletePhrase :
339                case IProblem.EndOfSource :
340                case IProblem.InvalidHexa :
341                case IProblem.InvalidOctal :
342                case IProblem.InvalidCharacterConstant :
343                case IProblem.InvalidEscape :
344                case IProblem.InvalidInput :
345                case IProblem.InvalidUnicodeEscape :
346                case IProblem.InvalidFloat :
347                case IProblem.NullSourceString :
348                case IProblem.UnterminatedString :
349                case IProblem.UnterminatedComment :
350                case IProblem.InvalidDigit :
351                    break;
352                default:
353                    this.usedOrIrrelevantProblems[i] = true;
354                    continue next;
355
356            }
357
358            int problemStart = problem.getSourceStart();
359            int problemEnd = problem.getSourceEnd();
360            if ((start <= problemStart) && (problemStart <= end) ||
361                    (start <= problemEnd) && (problemEnd <= end)) {
362                this.usedOrIrrelevantProblems[i] = true;
363                foundProblems = true;
364            }
365        }
366        return foundProblems;
367    }
368
369    @Override
370    public void endVisit(ExpressionStatement node) {
371        endVisitNode(node);
372        if ((node.getFlags() & ASTNode.RECOVERED) == 0) return;
373        Expression expression = node.getExpression();
374        if (expression.getNodeType() == ASTNode.ASSIGNMENT) {
375            Assignment assignment = (Assignmentexpression;
376            Expression rightHandSide = assignment.getRightHandSide();
377            if (rightHandSide.getNodeType() == ASTNode.SIMPLE_NAME) {
378                SimpleName simpleName = (SimpleNamerightHandSide;
379                if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIERsimpleName.getIdentifier().toCharArray())) {
380                    Expression expression2 =  assignment.getLeftHandSide();
381                    // unparent the expression to add it in the expression stateemnt
382                    expression2.setParent(nullnull);
383                    expression2.setFlags(expression2.getFlags() | ASTNode.RECOVERED);
384                    node.setExpression(expression2);
385                }
386            }
387        }
388    }
389
390    @Override
391    public void endVisit(ForStatement node) {
392        endVisitNode(node);
393        List initializers = node.initializers();
394        if (initializers.size() == 1) {
395            Expression expression = (Expressioninitializers.get(0);
396            if (expression.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
397                VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpressionexpression;
398                List fragments = variableDeclarationExpression.fragments();
399                for (int i = 0max = fragments.size(); i <maxi++) {
400                    VariableDeclarationFragment fragment = (VariableDeclarationFragmentfragments.get(i);
401                    SimpleName simpleName = fragment.getName();
402                    if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIERsimpleName.getIdentifier().toCharArray())) {
403                        fragments.remove(fragment);
404                        variableDeclarationExpression.setFlags(variableDeclarationExpression.getFlags() | ASTNode.RECOVERED);
405                    }
406                }
407            }
408        }
409    }
410
411    @Override
412    public void endVisit(VariableDeclarationStatement node) {
413        endVisitNode(node);
414        List fragments = node.fragments();
415        for (int i = 0max = fragments.size(); i <maxi++) {
416            VariableDeclarationFragment fragment = (VariableDeclarationFragmentfragments.get(i);
417            Expression expression = fragment.getInitializer();
418            if (expression == null) continue;
419            if ((expression.getFlags() & ASTNode.RECOVERED) == 0) continue;
420            if (expression.getNodeType() == ASTNode.SIMPLE_NAME) {
421                SimpleName simpleName = (SimpleNameexpression;
422                if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIERsimpleName.getIdentifier().toCharArray())) {
423                    fragment.setInitializer(null);
424                    fragment.setFlags(fragment.getFlags() | ASTNode.RECOVERED);
425                }
426            }
427        }
428    }
429
430    @Override
431    public void endVisit(NormalAnnotation node) {
432        endVisitNode(node);
433        // is inside diet part of the ast
434        if(this.blockDepth < 1) {
435            List values = node.values();
436            int size = values.size();
437            if (size > 0) {
438                MemberValuePair lastMemberValuePair = (MemberValuePair)values.get(size - 1);
439
440                int annotationEnd = node.getStartPosition() + node.getLength();
441                int lastMemberValuePairEnd = lastMemberValuePair.getStartPosition() + lastMemberValuePair.getLength();
442                if (annotationEnd == lastMemberValuePairEnd) {
443                    node.setFlags(node.getFlags() | ASTNode.RECOVERED);
444                }
445            }
446        }
447    }
448
449    @Override
450    public void endVisit(SingleMemberAnnotation node) {
451        endVisitNode(node);
452        // is inside diet part of the ast
453        if(this.blockDepth < 1) {
454            Expression value = node.getValue();
455            int annotationEnd = node.getStartPosition() + node.getLength();
456            int valueEnd = value.getStartPosition() + value.getLength();
457            if (annotationEnd == valueEnd) {
458                node.setFlags(node.getFlags() | ASTNode.RECOVERED);
459            }
460        }
461    }
462}
463
MembersX
ASTRecoveryPropagator:ASTRecoveryPropagator
ASTRecoveryPropagator:endVisit:Block:Block:Block:annotationEnd
ASTRecoveryPropagator:flagNodesWithInsertedTokensAtEnd:Block:expectedEndingToken
ASTRecoveryPropagator:endVisit:Block:Block:values
ASTRecoveryPropagator:endVisit:Block:fragments
ASTRecoveryPropagator:endVisitNode:Block:end
ASTRecoveryPropagator:endVisit:Block:Block:annotationEnd
ASTRecoveryPropagator:endVisit:Block:Block:Block:variableDeclarationExpression
ASTRecoveryPropagator:flagNodeWithInsertedTokens
ASTRecoveryPropagator:data
ASTRecoveryPropagator:endVisit:Block:Block:fragment
ASTRecoveryPropagator:visit
ASTRecoveryPropagator:visit:Block:visitChildren
ASTRecoveryPropagator:visitNode:Block:Block:end
ASTRecoveryPropagator:endVisitNode:Block:start
ASTRecoveryPropagator:markIncludedProblems:Block:Block:problemStart
ASTRecoveryPropagator:insertedTokensKind
ASTRecoveryPropagator:endVisit:Block:Block:Block:Block:expression2
ASTRecoveryPropagator:flagNodesWithInsertedTokensInside
ASTRecoveryPropagator:endVisit:Block:Block:rightHandSide
ASTRecoveryPropagator:markIncludedProblems:Block:foundProblems
ASTRecoveryPropagator:endVisit:Block:Block:expression
ASTRecoveryPropagator:insertedTokensFlagged
ASTRecoveryPropagator:endVisit:Block:Block:size
ASTRecoveryPropagator:endVisit:Block:Block:Block:lastMemberValuePairEnd
ASTRecoveryPropagator:stack
ASTRecoveryPropagator:flagNodeWithInsertedTokens:Block:Block:s
ASTRecoveryPropagator:markIncludedProblems:Block:Block:problemEnd
ASTRecoveryPropagator:flagNodesWithInsertedTokensInside:Block:end
ASTRecoveryPropagator:endVisit:Block:Block:Block:Block:fragment
ASTRecoveryPropagator:visitNode:Block:Block:start
ASTRecoveryPropagator:NOTHING
ASTRecoveryPropagator:flagNodesWithInsertedTokensAtEnd
ASTRecoveryPropagator:flagNodesWithInsertedTokensAtEnd:Block:Block:Block:parent
ASTRecoveryPropagator:endVisit:Block:Block:Block:lastMemberValuePair
ASTRecoveryPropagator:endVisit:Block:Block:Block:simpleName
ASTRecoveryPropagator:flagNodesWithInsertedTokensAtEnd:Block:Block:end
ASTRecoveryPropagator:removedTokensFlagged
ASTRecoveryPropagator:markIncludedProblems
ASTRecoveryPropagator:usedOrIrrelevantProblems
ASTRecoveryPropagator:flagNodesWithInsertedTokensAtEnd:Block:Block:start
ASTRecoveryPropagator:endVisit:Block:Block:value
ASTRecoveryPropagator:blockDepth
ASTRecoveryPropagator:endVisit:Block:expression
ASTRecoveryPropagator:problems
ASTRecoveryPropagator:ASTRecoveryPropagator:Block:Block:length
ASTRecoveryPropagator:replacedTokensFlagged
ASTRecoveryPropagator:ASTRecoveryPropagator:Block:Block:tokenCount
ASTRecoveryPropagator:insertedTokensPosition
ASTRecoveryPropagator:endingTokens
ASTRecoveryPropagator:visitNode
ASTRecoveryPropagator:flagNodesWithInsertedTokensAtEnd:Block:Block:flagParent
ASTRecoveryPropagator:endVisit
ASTRecoveryPropagator:endVisit:Block:initializers
ASTRecoveryPropagator:endVisit:Block:Block:assignment
ASTRecoveryPropagator:endVisitNode
ASTRecoveryPropagator:endVisit:Block:Block:valueEnd
ASTRecoveryPropagator:markIncludedProblems:Block:Block:problem
ASTRecoveryPropagator:lastEnd
ASTRecoveryPropagator:endVisit:Block:Block:Block:Block:simpleName
ASTRecoveryPropagator:flagNodesWithInsertedTokensInside:Block:start
ASTRecoveryPropagator:endVisit:Block:Block:Block:fragments
Members
X