1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.codeassist.select;
14 * Parser able to build specific completion parse nodes, given a cursorLocation.
16 * Cursor location denotes the position of the last character behind which completion
18 * -1 means completion at the very beginning of the source
19 * 0 means completion behind the first character
20 * n means completion behind the n-th character
23 import net.sourceforge.phpdt.internal.codeassist.impl.AssistParser;
24 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
25 import net.sourceforge.phpdt.internal.compiler.ast.AbstractVariableDeclaration;
26 import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration;
27 import net.sourceforge.phpdt.internal.compiler.ast.Argument;
28 import net.sourceforge.phpdt.internal.compiler.ast.ArrayAllocationExpression;
29 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
30 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
31 import net.sourceforge.phpdt.internal.compiler.ast.ExplicitConstructorCall;
32 import net.sourceforge.phpdt.internal.compiler.ast.Expression;
33 import net.sourceforge.phpdt.internal.compiler.ast.FieldReference;
34 import net.sourceforge.phpdt.internal.compiler.ast.ImportReference;
35 import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration;
36 import net.sourceforge.phpdt.internal.compiler.ast.MessageSend;
37 import net.sourceforge.phpdt.internal.compiler.ast.NameReference;
38 import net.sourceforge.phpdt.internal.compiler.ast.QualifiedAllocationExpression;
39 import net.sourceforge.phpdt.internal.compiler.ast.Reference;
40 import net.sourceforge.phpdt.internal.compiler.ast.SingleNameReference;
41 import net.sourceforge.phpdt.internal.compiler.ast.Statement;
42 import net.sourceforge.phpdt.internal.compiler.ast.SuperReference;
43 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
44 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
45 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
46 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
47 import net.sourceforge.phpdt.internal.compiler.parser.RecoveredType;
48 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
49 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
51 public class SelectionParser extends AssistParser {
55 public int selectionStart, selectionEnd;
57 public static final char[] SUPER = "super".toCharArray(); //$NON-NLS-1$
58 public static final char[] THIS = "this".toCharArray(); //$NON-NLS-1$
60 public SelectionParser(ProblemReporter problemReporter, boolean assertMode) {
61 super(problemReporter, assertMode);
63 public char[] assistIdentifier(){
64 return ((SelectionScanner)scanner).selectionIdentifier;
66 protected void attachOrphanCompletionNode(){
67 if (isOrphanCompletionNode){
68 AstNode orphan = this.assistNode;
69 isOrphanCompletionNode = false;
72 /* if in context of a type, then persists the identifier into a fake field return type */
73 if (currentElement instanceof RecoveredType){
74 RecoveredType recoveredType = (RecoveredType)currentElement;
75 /* filter out cases where scanner is still inside type header */
76 if (recoveredType.foundOpeningBrace) {
77 /* generate a pseudo field with a completion on type reference */
78 if (orphan instanceof TypeReference){
79 currentElement = currentElement.add(new SelectionOnFieldType((TypeReference)orphan), 0);
85 Statement statement = (Statement)wrapWithExplicitConstructorCallIfNeeded(orphan);
86 currentElement = currentElement.add(statement, 0);
87 currentToken = 0; // given we are not on an eof, we do not want side effects caused by looked-ahead token
91 private boolean checkRecoveredType() {
92 if (currentElement instanceof RecoveredType){
93 /* check if current awaiting identifier is the completion identifier */
94 if (this.indexOfAssistIdentifier() < 0) return false;
96 if ((lastErrorEndPosition >= selectionStart)
97 && (lastErrorEndPosition <= selectionEnd+1)){
100 RecoveredType recoveredType = (RecoveredType)currentElement;
101 /* filter out cases where scanner is still inside type header */
102 if (recoveredType.foundOpeningBrace) {
103 this.assistNode = this.getTypeReference(0);
104 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
105 this.isOrphanCompletionNode = true;
111 protected void classInstanceCreation(boolean alwaysQualified) {
113 // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
115 // ClassBodyopt produces a null item on the astStak if it produces NO class body
116 // An empty class body produces a 0 on the length stack.....
119 if (((length = astLengthStack[astLengthPtr]) == 1)
120 && (astStack[astPtr] == null)) {
122 if (this.indexOfAssistIdentifier() < 0) {
123 super.classInstanceCreation(alwaysQualified);
126 QualifiedAllocationExpression alloc;
129 alloc = new SelectionOnQualifiedAllocationExpression();
130 alloc.sourceEnd = endPosition; //the position has been stored explicitly
132 if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
133 expressionPtr -= length;
137 alloc.arguments = new Expression[length],
141 // trick to avoid creating a selection on type reference
142 char [] oldIdent = this.assistIdentifier();
143 this.setAssistIdentifier(null);
144 alloc.type = getTypeReference(0);
145 this.setAssistIdentifier(oldIdent);
147 //the default constructor with the correct number of argument
148 //will be created and added by the TC (see createsInternalConstructorWithBinding)
149 alloc.sourceStart = intStack[intPtr--];
150 pushOnExpressionStack(alloc);
152 this.assistNode = alloc;
153 this.lastCheckPoint = alloc.sourceEnd + 1;
155 this.restartRecovery = true; // force to restart in recovery mode
156 this.lastIgnoredToken = -1;
158 this.isOrphanCompletionNode = true;
160 super.classInstanceCreation(alwaysQualified);
164 protected void consumeArrayCreationExpression() {
165 // ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt
166 // ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt
168 super.consumeArrayCreationExpression();
170 ArrayAllocationExpression alloc = (ArrayAllocationExpression)expressionStack[expressionPtr];
171 if (alloc.type == assistNode){
173 this.restartRecovery = true; // force to restart in recovery mode
174 this.lastIgnoredToken = -1;
176 this.isOrphanCompletionNode = true;
179 protected void consumeEnterAnonymousClassBody() {
180 // EnterAnonymousClassBody ::= $empty
182 if (this.indexOfAssistIdentifier() < 0) {
183 super.consumeEnterAnonymousClassBody();
186 QualifiedAllocationExpression alloc;
187 AnonymousLocalTypeDeclaration anonymousType =
188 new AnonymousLocalTypeDeclaration(this.compilationUnit.compilationResult);
190 anonymousType.allocation = new SelectionOnQualifiedAllocationExpression(anonymousType);
191 markCurrentMethodWithLocalType();
192 pushOnAstStack(anonymousType);
194 alloc.sourceEnd = rParenPos; //the position has been stored explicitly
196 if ((argumentLength = expressionLengthStack[expressionLengthPtr--]) != 0) {
197 expressionPtr -= argumentLength;
201 alloc.arguments = new Expression[argumentLength],
205 // trick to avoid creating a selection on type reference
206 char [] oldIdent = this.assistIdentifier();
207 this.setAssistIdentifier(null);
208 alloc.type = getTypeReference(0);
209 this.setAssistIdentifier(oldIdent);
211 anonymousType.sourceEnd = alloc.sourceEnd;
212 //position at the type while it impacts the anonymous declaration
213 anonymousType.sourceStart = anonymousType.declarationSourceStart = alloc.type.sourceStart;
214 alloc.sourceStart = intStack[intPtr--];
215 pushOnExpressionStack(alloc);
218 this.lastCheckPoint = alloc.sourceEnd + 1;
220 this.restartRecovery = true; // force to restart in recovery mode
221 this.lastIgnoredToken = -1;
223 this.isOrphanCompletionNode = true;
225 anonymousType.bodyStart = scanner.currentPosition;
226 listLength = 0; // will be updated when reading super-interfaces
228 if (currentElement != null){
229 lastCheckPoint = anonymousType.bodyStart;
230 currentElement = currentElement.add(anonymousType, 0); // the recoveryTokenCheck will deal with the open brace
231 lastIgnoredToken = -1;
234 protected void consumeEnterVariable() {
235 // EnterVariable ::= $empty
236 // do nothing by default
238 super.consumeEnterVariable();
240 AbstractVariableDeclaration variable = (AbstractVariableDeclaration) astStack[astPtr];
241 if (variable.type == assistNode){
243 this.restartRecovery = true; // force to restart in recovery mode
244 this.lastIgnoredToken = -1;
246 isOrphanCompletionNode = false; // already attached inside variable decl
250 protected void consumeExitVariableWithInitialization() {
251 super.consumeExitVariableWithInitialization();
253 // does not keep the initialization if selection is not inside
254 AbstractVariableDeclaration variable = (AbstractVariableDeclaration) astStack[astPtr];
255 int start = variable.initialization.sourceStart;
256 int end = variable.initialization.sourceEnd;
257 if ((selectionStart < start) && (selectionEnd < start) ||
258 (selectionStart > end) && (selectionEnd > end)) {
259 variable.initialization = null;
263 protected void consumeFieldAccess(boolean isSuperAccess) {
264 // FieldAccess ::= Primary '.' 'Identifier'
265 // FieldAccess ::= 'super' '.' 'Identifier'
267 if (this.indexOfAssistIdentifier() < 0) {
268 super.consumeFieldAccess(isSuperAccess);
271 FieldReference fieldReference =
272 new SelectionOnFieldReference(
273 identifierStack[identifierPtr],
274 identifierPositionStack[identifierPtr--]);
275 identifierLengthPtr--;
276 if (isSuperAccess) { //considerates the fieldReferenceerence beginning at the 'super' ....
277 fieldReference.sourceStart = intStack[intPtr--];
278 fieldReference.receiver = new SuperReference(fieldReference.sourceStart, endPosition);
279 pushOnExpressionStack(fieldReference);
280 } else { //optimize push/pop
281 if ((fieldReference.receiver = expressionStack[expressionPtr]).isThis()) { //fieldReferenceerence begins at the this
282 fieldReference.sourceStart = fieldReference.receiver.sourceStart;
284 expressionStack[expressionPtr] = fieldReference;
286 assistNode = fieldReference;
287 this.lastCheckPoint = fieldReference.sourceEnd + 1;
289 this.restartRecovery = true; // force to restart in recovery mode
290 this.lastIgnoredToken = -1;
292 this.isOrphanCompletionNode = true;
294 protected void consumeFormalParameter() {
295 if (this.indexOfAssistIdentifier() < 0) {
296 super.consumeFormalParameter();
299 identifierLengthPtr--;
300 char[] name = identifierStack[identifierPtr];
301 long namePositions = identifierPositionStack[identifierPtr--];
302 TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]);
305 new SelectionOnArgumentName(
309 intStack[intPtr + 1] & ~AccDeprecated); // modifiers
313 this.lastCheckPoint = (int) namePositions;
314 isOrphanCompletionNode = true;
317 this.restartRecovery = true; // force to restart in recovery mode
318 this.lastIgnoredToken = -1;
321 /* if incomplete method header, listLength counter will not have been reset,
322 indicating that some arguments are available on the stack */
326 protected void consumeInstanceOfExpression(int op) {
327 if (indexOfAssistIdentifier() < 0) {
328 super.consumeInstanceOfExpression(op);
330 getTypeReference(intStack[intPtr--]);
331 this.isOrphanCompletionNode = true;
332 this.restartRecovery = true;
333 this.lastIgnoredToken = -1;
336 protected void consumeMethodInvocationName() {
337 // MethodInvocation ::= Name '(' ArgumentListopt ')'
339 // when the name is only an identifier...we have a message send to "this" (implicit)
341 char[] selector = identifierStack[identifierPtr];
343 if(selector == this.assistIdentifier()) {
344 if(CharOperation.equals(selector, SUPER)) {
345 accessMode = ExplicitConstructorCall.Super;
346 } else if(CharOperation.equals(selector, THIS)) {
347 accessMode = ExplicitConstructorCall.This;
349 super.consumeMethodInvocationName();
353 super.consumeMethodInvocationName();
357 final ExplicitConstructorCall constructorCall = new SelectionOnExplicitConstructorCall(accessMode);
358 constructorCall.sourceEnd = rParenPos;
359 constructorCall.sourceStart = (int) (identifierPositionStack[identifierPtr] >>> 32);
361 if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
362 expressionPtr -= length;
363 System.arraycopy(expressionStack, expressionPtr + 1, constructorCall.arguments = new Expression[length], 0, length);
367 pushOnAstStack(constructorCall);
368 this.restartRecovery = true; // force to restart in recovery mode
369 this.lastIgnoredToken = -1;
371 pushOnExpressionStack(new Expression(){
372 public TypeBinding resolveType(BlockScope scope) {
373 constructorCall.resolve(scope);
378 this.assistNode = constructorCall;
379 this.lastCheckPoint = constructorCall.sourceEnd + 1;
380 this.isOrphanCompletionNode = true;
382 protected void consumeMethodInvocationPrimary() {
383 //optimize the push/pop
384 //MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')'
386 char[] selector = identifierStack[identifierPtr];
388 if(selector == this.assistIdentifier()) {
389 if(CharOperation.equals(selector, SUPER)) {
390 accessMode = ExplicitConstructorCall.Super;
391 } else if(CharOperation.equals(selector, THIS)) {
392 accessMode = ExplicitConstructorCall.This;
394 super.consumeMethodInvocationPrimary();
398 super.consumeMethodInvocationPrimary();
402 final ExplicitConstructorCall constructorCall = new SelectionOnExplicitConstructorCall(accessMode);
403 constructorCall.sourceEnd = rParenPos;
405 if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
406 expressionPtr -= length;
407 System.arraycopy(expressionStack, expressionPtr + 1, constructorCall.arguments = new Expression[length], 0, length);
409 constructorCall.qualification = expressionStack[expressionPtr--];
410 constructorCall.sourceStart = constructorCall.qualification.sourceStart;
413 pushOnAstStack(constructorCall);
414 this.restartRecovery = true; // force to restart in recovery mode
415 this.lastIgnoredToken = -1;
417 pushOnExpressionStack(new Expression(){
418 public TypeBinding resolveType(BlockScope scope) {
419 constructorCall.resolve(scope);
425 this.assistNode = constructorCall;
426 this.lastCheckPoint = constructorCall.sourceEnd + 1;
427 this.isOrphanCompletionNode = true;
429 protected void consumeTypeImportOnDemandDeclarationName() {
430 // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
431 /* push an ImportRef build from the last name
432 stored in the identifier stack. */
436 /* no need to take action if not inside assist identifiers */
437 if ((index = indexOfAssistIdentifier()) < 0) {
438 super.consumeTypeImportOnDemandDeclarationName();
441 /* retrieve identifiers subset and whole positions, the assist node positions
442 should include the entire replaced source. */
443 int length = identifierLengthStack[identifierLengthPtr];
444 char[][] subset = identifierSubSet(index+1); // include the assistIdentifier
445 identifierLengthPtr--;
446 identifierPtr -= length;
447 long[] positions = new long[length];
449 identifierPositionStack,
455 /* build specific assist node on import statement */
456 ImportReference reference = this.createAssistImportReference(subset, positions);
457 reference.onDemand = true;
458 assistNode = reference;
459 this.lastCheckPoint = reference.sourceEnd + 1;
461 pushOnAstStack(reference);
463 if (currentToken == TokenNameSEMICOLON){
464 reference.declarationSourceEnd = scanner.currentPosition - 1;
466 reference.declarationSourceEnd = (int) positions[length-1];
468 //endPosition is just before the ;
469 reference.declarationSourceStart = intStack[intPtr--];
470 // flush annotations defined prior to import statements
471 reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd);
474 if (currentElement != null){
475 lastCheckPoint = reference.declarationSourceEnd+1;
476 currentElement = currentElement.add(reference, 0);
477 lastIgnoredToken = -1;
478 restartRecovery = true; // used to avoid branching back into the regular automaton
481 public ImportReference createAssistImportReference(char[][] tokens, long[] positions){
482 return new SelectionOnImportReference(tokens, positions);
484 public ImportReference createAssistPackageReference(char[][] tokens, long[] positions){
485 return new SelectionOnPackageReference(tokens, positions);
487 protected LocalDeclaration createLocalDeclaration(Expression initialization,char[] name,int sourceStart,int sourceEnd) {
488 if (this.indexOfAssistIdentifier() < 0) {
489 return super.createLocalDeclaration(initialization, name, sourceStart, sourceEnd);
491 SelectionOnLocalName local = new SelectionOnLocalName(initialization, name, sourceStart, sourceEnd);
492 this.assistNode = local;
493 this.lastCheckPoint = sourceEnd + 1;
495 this.restartRecovery = true; // force to restart in recovery mode
496 this.lastIgnoredToken = -1;
501 public NameReference createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] name, long[] positions){
502 return new SelectionOnQualifiedNameReference(
507 public TypeReference createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] name, long[] positions){
508 return new SelectionOnQualifiedTypeReference(
513 public NameReference createSingleAssistNameReference(char[] name, long position) {
514 return new SelectionOnSingleNameReference(name, position);
516 public TypeReference createSingleAssistTypeReference(char[] name, long position) {
517 return new SelectionOnSingleTypeReference(name, position);
519 public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int selectionStart, int selectionEnd) {
521 this.selectionStart = selectionStart;
522 this.selectionEnd = selectionEnd;
523 SelectionScanner selectionScanner = (SelectionScanner)this.scanner;
524 selectionScanner.selectionIdentifier = null;
525 selectionScanner.selectionStart = selectionStart;
526 selectionScanner.selectionEnd = selectionEnd;
527 return this.dietParse(sourceUnit, compilationResult);
529 protected NameReference getUnspecifiedReference() {
530 /* build a (unspecified) NameReference which may be qualified*/
534 /* no need to take action if not inside completed identifiers */
535 if ((completionIndex = indexOfAssistIdentifier()) < 0) {
536 return super.getUnspecifiedReference();
539 int length = identifierLengthStack[identifierLengthPtr];
540 if (CharOperation.equals(assistIdentifier(), SUPER)){
542 if (completionIndex > 0){ // qualified super
543 // discard 'super' from identifier stacks
544 identifierLengthStack[identifierLengthPtr] = completionIndex;
545 int ptr = identifierPtr -= (length - completionIndex);
547 new SelectionOnQualifiedSuperReference(
549 (int)(identifierPositionStack[ptr+1] >>> 32),
550 (int) identifierPositionStack[ptr+1]);
551 } else { // standard super
552 identifierPtr -= length;
553 identifierLengthPtr--;
554 reference = new SelectionOnSuperReference((int)(identifierPositionStack[identifierPtr+1] >>> 32), (int) identifierPositionStack[identifierPtr+1]);
556 pushOnAstStack(reference);
557 this.assistNode = reference;
558 this.lastCheckPoint = reference.sourceEnd + 1;
559 if (!diet || dietInt != 0){
560 this.restartRecovery = true; // force to restart in recovery mode
561 this.lastIgnoredToken = -1;
563 this.isOrphanCompletionNode = true;
564 return new SingleNameReference(new char[0], 0); // dummy reference
566 NameReference nameReference;
567 /* retrieve identifiers subset and whole positions, the completion node positions
568 should include the entire replaced source. */
569 char[][] subset = identifierSubSet(completionIndex);
570 identifierLengthPtr--;
571 identifierPtr -= length;
572 long[] positions = new long[length];
574 identifierPositionStack,
579 /* build specific completion on name reference */
580 if (completionIndex == 0) {
581 /* completion inside first identifier */
582 nameReference = this.createSingleAssistNameReference(assistIdentifier(), positions[0]);
584 /* completion inside subsequent identifier */
585 nameReference = this.createQualifiedAssistNameReference(subset, assistIdentifier(), positions);
587 assistNode = nameReference;
588 this.lastCheckPoint = nameReference.sourceEnd + 1;
590 this.restartRecovery = true; // force to restart in recovery mode
591 this.lastIgnoredToken = -1;
593 this.isOrphanCompletionNode = true;
594 return nameReference;
597 * Copy of code from superclass with the following change:
598 * In the case of qualified name reference if the cursor location is on the
599 * qualified name reference, then create a CompletionOnQualifiedNameReference
602 protected NameReference getUnspecifiedReferenceOptimized() {
604 int index = indexOfAssistIdentifier();
605 NameReference reference = super.getUnspecifiedReferenceOptimized();
609 this.restartRecovery = true; // force to restart in recovery mode
610 this.lastIgnoredToken = -1;
612 this.isOrphanCompletionNode = true;
616 public void initializeScanner(){
617 this.scanner = new SelectionScanner(this.assertMode);
619 protected MessageSend newMessageSend() {
620 // '(' ArgumentListopt ')'
621 // the arguments are on the expression stack
623 char[] selector = identifierStack[identifierPtr];
624 if (selector != this.assistIdentifier()){
625 return super.newMessageSend();
627 MessageSend messageSend = new SelectionOnMessageSend();
629 if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
630 expressionPtr -= length;
634 messageSend.arguments = new Expression[length],
638 assistNode = messageSend;
640 this.restartRecovery = true; // force to restart in recovery mode
641 this.lastIgnoredToken = -1;
644 this.isOrphanCompletionNode = true;
647 public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int selectionStart, int selectionEnd) {
649 this.selectionStart = selectionStart;
650 this.selectionEnd = selectionEnd;
651 SelectionScanner selectionScanner = (SelectionScanner)this.scanner;
652 selectionScanner.selectionIdentifier = null;
653 selectionScanner.selectionStart = selectionStart;
654 selectionScanner.selectionEnd = selectionEnd;
655 return this.parse(sourceUnit, compilationResult);
658 * Reset context so as to resume to regular parse loop
659 * If unable to reset for resuming, answers false.
661 * Move checkpoint location, reset internal stacks and
662 * decide which grammar goal is activated.
664 protected boolean resumeAfterRecovery() {
666 /* if reached assist node inside method body, but still inside nested type,
667 should continue in diet mode until the end of the method body */
668 if (this.assistNode != null
669 && !(referenceContext instanceof CompilationUnitDeclaration)){
670 currentElement.preserveEnclosingBlocks();
671 if (currentElement.enclosingType() == null){
676 return super.resumeAfterRecovery();
679 public void selectionIdentifierCheck(){
680 if (checkRecoveredType()) return;
682 public void setAssistIdentifier(char[] assistIdent){
683 ((SelectionScanner)scanner).selectionIdentifier = assistIdent;
686 * Update recovery state based on current parser/scanner state
688 protected void updateRecoveryState() {
690 /* expose parser state to recovery state */
691 currentElement.updateFromParserState();
693 /* may be able to retrieve completionNode as an orphan, and then attach it */
694 this.selectionIdentifierCheck();
695 this.attachOrphanCompletionNode();
697 /* check and update recovered state based on current token,
698 this action is also performed when shifting token after recovery
701 this.recoveryTokenCheck();