Package org.aspectj.org.eclipse.jdt.internal.compiler.parser

Source Code of org.aspectj.org.eclipse.jdt.internal.compiler.parser.RecoveredMethod

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.compiler.parser;

import org.aspectj.org.eclipse.jdt.core.compiler.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Block;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SuperReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.Util;

/**
* Internal method structure for parsing recovery
*/

public class RecoveredMethod extends RecoveredElement implements TerminalTokens {

  public AbstractMethodDeclaration methodDeclaration;

  public RecoveredType[] localTypes;
  public int localTypeCount;

  public RecoveredBlock methodBody;
  public boolean discardBody = true;

public RecoveredMethod(AbstractMethodDeclaration methodDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
  super(parent, bracketBalance, parser);
  this.methodDeclaration = methodDeclaration;
  this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
  if(this.foundOpeningBrace) {
    this.bracketBalance++;
  }
}
/*
* Record a nested block declaration
*/
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {

  /* default behavior is to delegate recording to parent if any,
  do not consider elements passed the known end (if set)
  it must be belonging to an enclosing element
  */
  if (methodDeclaration.declarationSourceEnd > 0
    && nestedBlockDeclaration.sourceStart
      > methodDeclaration.declarationSourceEnd){
        if (this.parent == null){
          return this; // ignore
        } else {
          return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
        }
  }
  /* consider that if the opening brace was not found, it is there */
  if (!foundOpeningBrace){
    foundOpeningBrace = true;
    this.bracketBalance++;
  }

  methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
  if (nestedBlockDeclaration.sourceEnd == 0) return methodBody;
  return this;
}
/*
* Record a field declaration
*/
public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {

  /* local variables inside method can only be final and non void */
  char[][] fieldTypeName;
  if ((fieldDeclaration.modifiers & ~ClassFileConstants.AccFinal) != 0 // local var can only be final
    || (fieldDeclaration.type == null) // initializer
    || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void
      && CharOperation.equals(fieldTypeName[0], TypeBinding.VOID.sourceName()))){

    if (this.parent == null){
      return this; // ignore
    } else {
      this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
      return this.parent.add(fieldDeclaration, bracketBalanceValue);
    }
  }
  /* default behavior is to delegate recording to parent if any,
  do not consider elements passed the known end (if set)
  it must be belonging to an enclosing element
  */
  if (methodDeclaration.declarationSourceEnd > 0
    && fieldDeclaration.declarationSourceStart
      > methodDeclaration.declarationSourceEnd){
    if (this.parent == null){
      return this; // ignore
    } else {
      return this.parent.add(fieldDeclaration, bracketBalanceValue);
    }
  }
  /* consider that if the opening brace was not found, it is there */
  if (!foundOpeningBrace){
    foundOpeningBrace = true;
    this.bracketBalance++;
  }
  // still inside method, treat as local variable
  return this; // ignore
}
/*
* Record a local declaration - regular method should have been created a block body
*/
public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {

  /* local variables inside method can only be final and non void */
/* 
  char[][] localTypeName;
  if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final
    || (localDeclaration.type == null) // initializer
    || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void
      && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){

    if (this.parent == null){
      return this; // ignore
    } else {
      this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
      return this.parent.add(localDeclaration, bracketBalance);
    }
  }
*/
  /* do not consider a type starting passed the type end (if set)
    it must be belonging to an enclosing type */
  if (methodDeclaration.declarationSourceEnd != 0
    && localDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
     
    if (this.parent == null) {
      return this; // ignore
    } else {
      return this.parent.add(localDeclaration, bracketBalanceValue);
    }
  }
  if (methodBody == null){
    Block block = new Block(0);
    block.sourceStart = methodDeclaration.bodyStart;
    RecoveredElement currentBlock = this.add(block, 1);
    if (this.bracketBalance > 0){
      for (int i = 0; i < this.bracketBalance - 1; i++){
        currentBlock = currentBlock.add(new Block(0), 1);
      }
      this.bracketBalance = 1;
    }
    return currentBlock.add(localDeclaration, bracketBalanceValue);
  }
  return methodBody.add(localDeclaration, bracketBalanceValue, true);
}
/*
* Record a statement - regular method should have been created a block body
*/
public RecoveredElement add(Statement statement, int bracketBalanceValue) {

  /* do not consider a type starting passed the type end (if set)
    it must be belonging to an enclosing type */
  if (methodDeclaration.declarationSourceEnd != 0
    && statement.sourceStart > methodDeclaration.declarationSourceEnd){

    if (this.parent == null) {
      return this; // ignore
    } else {
      return this.parent.add(statement, bracketBalanceValue);
    }
  }
  if (methodBody == null){
    Block block = new Block(0);
    block.sourceStart = methodDeclaration.bodyStart;
    RecoveredElement currentBlock = this.add(block, 1);
    if (this.bracketBalance > 0){
      for (int i = 0; i < this.bracketBalance - 1; i++){
        currentBlock = currentBlock.add(new Block(0), 1);
      }
      this.bracketBalance = 1;
    }
    return currentBlock.add(statement, bracketBalanceValue);
  }
  return methodBody.add(statement, bracketBalanceValue, true)
}
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {

  /* do not consider a type starting passed the type end (if set)
    it must be belonging to an enclosing type */
  if (methodDeclaration.declarationSourceEnd != 0
    && typeDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
     
    if (this.parent == null) {
      return this; // ignore
    }
    return this.parent.add(typeDeclaration, bracketBalanceValue);
  }
  if ((typeDeclaration.bits & ASTNode.IsLocalType) != 0 || this.parser().methodRecoveryActivated || this.parser().statementRecoveryActivated){
    if (methodBody == null){
      Block block = new Block(0);
      block.sourceStart = methodDeclaration.bodyStart;
      this.add(block, 1);
    }
    return methodBody.add(typeDeclaration, bracketBalanceValue, true)
  }
  switch (TypeDeclaration.kind(typeDeclaration.modifiers)) {
    case TypeDeclaration.INTERFACE_DECL :
    case TypeDeclaration.ANNOTATION_TYPE_DECL :
      this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
      if (this.parent == null) {
        return this; // ignore
      }
      // close the constructor
      return this.parent.add(typeDeclaration, bracketBalanceValue);
  }
  if (localTypes == null) {
    localTypes = new RecoveredType[5];
    localTypeCount = 0;
  } else {
    if (localTypeCount == localTypes.length) {
      System.arraycopy(
        localTypes,
        0,
        (localTypes = new RecoveredType[2 * localTypeCount]),
        0,
        localTypeCount);
    }
  }
  RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
  localTypes[localTypeCount++] = element;

  /* consider that if the opening brace was not found, it is there */
  if (!foundOpeningBrace){
    foundOpeningBrace = true;
    this.bracketBalance++;
  }
  return element;
}
public boolean bodyStartsAtHeaderEnd(){
  return methodDeclaration.bodyStart == methodDeclaration.sourceEnd+1;
}
/*
* Answer the associated parsed structure
*/
public ASTNode parseTree(){
  return methodDeclaration;
}
/*
* Answer the very source end of the corresponding parse node
*/
public int sourceEnd(){
  return this.methodDeclaration.declarationSourceEnd;
}
public String toString(int tab) {
  StringBuffer result = new StringBuffer(tabString(tab));
  result.append("Recovered method:\n"); //$NON-NLS-1$
  this.methodDeclaration.print(tab + 1, result);
  if (this.localTypes != null) {
    for (int i = 0; i < this.localTypeCount; i++) {
      result.append("\n"); //$NON-NLS-1$
      result.append(this.localTypes[i].toString(tab + 1));
    }
  }
  if (this.methodBody != null) {
    result.append("\n"); //$NON-NLS-1$
    result.append(this.methodBody.toString(tab + 1));
  }
  return result.toString();
}
/*
* Update the bodyStart of the corresponding parse node
*/
public void updateBodyStart(int bodyStart){
  this.foundOpeningBrace = true;   
  this.methodDeclaration.bodyStart = bodyStart;
}
public AbstractMethodDeclaration updatedMethodDeclaration(){

  if (methodBody != null){
    Block block = methodBody.updatedBlock();
    if (block != null){
      methodDeclaration.statements = block.statements;

      /* first statement might be an explict constructor call destinated to a special slot */
      if (methodDeclaration.isConstructor()) {
        ConstructorDeclaration constructor = (ConstructorDeclaration)methodDeclaration;
        if (methodDeclaration.statements != null
          && methodDeclaration.statements[0] instanceof ExplicitConstructorCall){
          constructor.constructorCall = (ExplicitConstructorCall)methodDeclaration.statements[0];
          int length = methodDeclaration.statements.length;
          System.arraycopy(
            methodDeclaration.statements,
            1,
            (methodDeclaration.statements = new Statement[length-1]),
            0,
            length-1);
          }
          if (constructor.constructorCall == null){ // add implicit constructor call
            constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
          }
      }
    }
  }
  if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalType;
  return methodDeclaration;
}
/*
* Update the corresponding parse node from parser state which
* is about to disappear because of restarting recovery
*/
public void updateFromParserState(){
  // if parent is null then recovery already occured in diet parser.
  if(this.bodyStartsAtHeaderEnd() && this.parent != null){
    Parser parser = this.parser();
    /* might want to recover arguments or thrown exceptions */
    if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
      /* has consumed the arguments - listed elements must be thrown exceptions */
      if (methodDeclaration.sourceEnd == parser.rParenPos) {
       
        // protection for bugs 15142
        int length = parser.astLengthStack[parser.astLengthPtr];
        int astPtr = parser.astPtr - length;
        boolean canConsume = astPtr >= 0;
        if(canConsume) {
          if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
            canConsume = false;
          }
          for (int i = 1, max = length + 1; i < max; i++) {
            if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) {
              canConsume = false;
            }
          }
        }
        if (canConsume){
          parser.consumeMethodHeaderThrowsClause();
          // will reset typeListLength to zero
          // thus this check will only be performed on first errorCheck after void foo() throws X, Y,
        } else {
          parser.listLength = 0;
        }
      } else {
        /* has not consumed arguments yet, listed elements must be arguments */
        if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON){
          /* if currentToken is parenthesis this last argument is a method/field signature */
          parser.astLengthStack[parser.astLengthPtr] --;
          parser.astPtr --;
          parser.listLength --;
          parser.currentToken = 0;
        }
        int argLength = parser.astLengthStack[parser.astLengthPtr];
        int argStart = parser.astPtr - argLength + 1;
        boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used
       
        // remove unfinished annotation nodes
        MemberValuePair[] memberValuePairs = null;
        if (argLength > 0 && parser.astStack[parser.astPtr] instanceof MemberValuePair) {
          System.arraycopy(parser.astStack, argStart, memberValuePairs = new MemberValuePair[argLength], 0, argLength);
          parser.astLengthPtr--;
          parser.astPtr -= argLength;
         
          argLength = parser.astLengthStack[parser.astLengthPtr];
          argStart = parser.astPtr - argLength + 1;
          needUpdateRParenPos = true;
        }
       
        // to compute bodyStart, and thus used to set next checkpoint.
        int count;
        for (count = 0; count < argLength; count++){
          ASTNode aNode = parser.astStack[argStart+count];
          if(aNode instanceof Argument) {
            Argument argument = (Argument)aNode;
            /* cannot be an argument if non final */
            char[][] argTypeName = argument.type.getTypeName();
            if ((argument.modifiers & ~ClassFileConstants.AccFinal) != 0
              || (argTypeName.length == 1
                && CharOperation.equals(argTypeName[0], TypeBinding.VOID.sourceName()))){
              parser.astLengthStack[parser.astLengthPtr] = count;
              parser.astPtr = argStart+count-1;
              parser.listLength = count;
              parser.currentToken = 0;
              break;
            }
            if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1;
          } else {
            parser.astLengthStack[parser.astLengthPtr] = count;
            parser.astPtr = argStart+count-1;
            parser.listLength = count;
            parser.currentToken = 0;
            break;
          }
        }
        if (parser.listLength > 0 && parser.astLengthPtr > 0){
         
          // protection for bugs 15142
          int length = parser.astLengthStack[parser.astLengthPtr];
          int astPtr = parser.astPtr - length;
          boolean canConsume = astPtr >= 0;
          if(canConsume) {
            if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
              canConsume = false;
            }
            for (int i = 1, max = length + 1; i < max; i++) {
              if(!(parser.astStack[astPtr + i ] instanceof Argument)) {
                canConsume = false;
              }
            }
          }
          if(canConsume) {
            parser.consumeMethodHeaderRightParen();
            /* fix-up positions, given they were updated against rParenPos, which did not get set */
            if (parser.currentElement == this){ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */
              methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length-1].sourceEnd;
              methodDeclaration.bodyStart = methodDeclaration.sourceEnd+1;
              parser.lastCheckPoint = methodDeclaration.bodyStart;
            }
          }
        }
       
        if(memberValuePairs != null) {
          System.arraycopy(memberValuePairs, 0, parser.astStack, parser.astPtr + 1, memberValuePairs.length);
          parser.astPtr += memberValuePairs.length;
          parser.astLengthStack[++parser.astLengthPtr] = memberValuePairs.length;
        }
      }
    }
  }
}
public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
  if(this.methodDeclaration.isAnnotationMethod()) {
    this.updateSourceEndIfNecessary(braceStart, braceEnd);
    if(!this.foundOpeningBrace && this.parent != null) {
      return this.parent.updateOnClosingBrace(braceStart, braceEnd);
    }
    return this;
  }
  if(this.parent != null && this.parent instanceof RecoveredType) {
    int modifiers = ((RecoveredType)this.parent).typeDeclaration.modifiers;
    if (TypeDeclaration.kind(modifiers) == TypeDeclaration.INTERFACE_DECL) {
      if (!this.foundOpeningBrace) {
        this.updateSourceEndIfNecessary(braceStart - 1, braceStart - 1);
        return this.parent.updateOnClosingBrace(braceStart, braceEnd);
      }
    }
  }
  return super.updateOnClosingBrace(braceStart, braceEnd);
}
/*
* An opening brace got consumed, might be the expected opening one of the current element,
* in which case the bodyStart is updated.
*/
public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){

  /* in case the opening brace is close enough to the signature */
  if (bracketBalance == 0){
    /*
      if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd)
        != parser.scanner.searchLineNumber(braceEnd)){
     */
    switch(parser().lastIgnoredToken){
      case -1 :
      case TokenNamethrows :
        break;
      default:
        this.foundOpeningBrace = true;       
        bracketBalance = 1; // pretend the brace was already there
    }
  } 
  return super.updateOnOpeningBrace(braceStart, braceEnd);
}
public void updateParseTree(){
  this.updatedMethodDeclaration();
}
/*
* Update the declarationSourceEnd of the corresponding parse node
*/
public void updateSourceEndIfNecessary(int braceStart, int braceEnd){
  if (this.methodDeclaration.declarationSourceEnd == 0) {
    if(parser().rBraceSuccessorStart >= braceEnd) {
      this.methodDeclaration.declarationSourceEnd = parser().rBraceEnd;
      this.methodDeclaration.bodyEnd = parser().rBraceStart;
    } else {
      this.methodDeclaration.declarationSourceEnd = braceEnd;
      this.methodDeclaration.bodyEnd  = braceStart - 1;
    }
  }
}
void attach(TypeParameter[] parameters, int startPos) {
  if(methodDeclaration.modifiers != ClassFileConstants.AccDefault) return;
 
  int lastParameterEnd = parameters[parameters.length - 1].sourceEnd;
 
  Parser parser = this.parser();
  Scanner scanner = parser.scanner;
  if(Util.getLineNumber(methodDeclaration.declarationSourceStart, scanner.lineEnds, 0, scanner.linePtr)
      != Util.getLineNumber(lastParameterEnd, scanner.lineEnds, 0, scanner.linePtr)) return;
 
  if(parser.modifiersSourceStart > lastParameterEnd
      && parser.modifiersSourceStart < methodDeclaration.declarationSourceStart) return;
 
  if (this.methodDeclaration instanceof MethodDeclaration) {
    ((MethodDeclaration)this.methodDeclaration).typeParameters = parameters;
    this.methodDeclaration.declarationSourceStart = startPos;
  } else if (this.methodDeclaration instanceof ConstructorDeclaration){
    ((ConstructorDeclaration)this.methodDeclaration).typeParameters = parameters;
    this.methodDeclaration.declarationSourceStart = startPos;
  }
}
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.compiler.parser.RecoveredMethod

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.