Package org.eclipse.php.internal.core.typeinference

Source Code of org.eclipse.php.internal.core.typeinference.DeclarationScope

/*******************************************************************************
* Copyright (c) 2009, 2014 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
*     Zend Technologies
*     Dawid PakuĊ‚a [414814]
*******************************************************************************/
package org.eclipse.php.internal.core.typeinference;

import java.util.*;

import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.statements.Statement;
import org.eclipse.dltk.ti.IContext;
import org.eclipse.php.internal.core.compiler.ast.nodes.*;

/**
* Variable declaration scope. Each scope contains mapping between variable name
* and its possible declarations.
*
* @author michael
*/
public class DeclarationScope {

  private Map<String, LinkedList<Declaration>> decls = new HashMap<String, LinkedList<Declaration>>();
  private IContext context;
  private Stack<Statement> innerBlocks = new Stack<Statement>();

  public DeclarationScope(IContext context) {
    this.context = context;
  }

  /**
   * Returns context associated with this scope
   *
   * @return
   */
  public IContext getContext() {
    return context;
  }

  /**
   * This must be called when entering inner conditional block.
   */
  public void enterInnerBlock(Statement s) {
    if (!innerBlocks.isEmpty() && innerBlocks.peek() == s) {
      return;
    }
    innerBlocks.push(s);
  }

  /**
   * This must be called when exiting inner conditional block.
   */
  public void exitInnerBlock() {
    if (!innerBlocks.isEmpty()) {
      innerBlocks.pop();
    }
  }

  public int getInnerBlockLevel() {
    return innerBlocks.size();
  }

  /**
   * Returns all declarations for all variables
   *
   * @return
   */
  public Map<String, LinkedList<Declaration>> getAllDeclarations() {
    return decls;
  }

  /**
   * Returns all possible variable declarations for the given variable name in
   * current scope.
   *
   * @param varName
   */
  public Declaration[] getDeclarations(String varName) {
    List<Declaration> result = new LinkedList<Declaration>();
    LinkedList<Declaration> varDecls = decls.get(varName);
    if (varDecls != null) {
      for (Declaration decl : varDecls) {
        if (decl != null) {
          result.add(decl);
        }
      }
    }
    return (Declaration[]) result.toArray(new Declaration[result.size()]);
  }

  /**
   * Adds possible variable declaration
   *
   * @param varName
   *            Variable name
   * @param declNode
   *            AST declaration statement node
   */
  public void addDeclaration(String varName, ASTNode declNode) {
    LinkedList<Declaration> varDecls = decls.get(varName);
    if (varDecls == null) {
      varDecls = new LinkedList<Declaration>();
      decls.put(varName, varDecls);
    }

    int level = innerBlocks.size();

    // TODO check ArrayCreation,ArrayVariableReference
    // skip all inner conditional blocks statements, since we've reached
    // a re-declaration here
    while (varDecls.size() > level + 1) {
      varDecls.removeLast();
    }

    // preserve place for declarations in outer conditional blocks
    // in case we haven't reached any declaration untill now
    while (varDecls.size() < level) {
      varDecls.addLast(null);
    }
    if (declNode instanceof Assignment
        && (((Assignment) declNode).getVariable() instanceof ArrayVariableReference)) {
      int index = varDecls.size() - 1;
      while (index >= 0) {
        Declaration decl = varDecls.get(index);
        if (decl instanceof ArrayDeclaration) {
          ArrayDeclaration arrayDeclaration = (ArrayDeclaration) decl;
          arrayDeclaration.addDeclaration(declNode);
          return;
        }
        index--;
      }
    }
    if (varDecls.size() > level) {
      Declaration decl = varDecls.get(level);
      // The case that the node is inside another node
      if (decl != null) {
        if (level > 0) {
          Statement block = innerBlocks.get(level - 1);
          if (isInSameBlock(block, decl.getNode(), declNode)) {
            // replace existing declaration with a new one (leave
            // 'isGlobal' flag the same)
            decl.setNode(declNode);
            return;
          }
        } else { // The node is the top node.
              // replace existing declaration with a new one
              // (leave
              // 'isGlobal' flag the same)
          if (decl instanceof ArrayDeclaration) {
            decl = new Declaration(
                declNode instanceof GlobalStatement, declNode);
            varDecls.set(level, decl);
          } else if (!(declNode instanceof Assignment && (((Assignment) declNode)
              .getVariable() instanceof ArrayVariableReference))) {
            // bug 414814
            decl.setNode(declNode);
          }

          return;
        }
      }
    }
    // add new declaration
    if (declNode instanceof Assignment
        && (((Assignment) declNode).getValue() instanceof ArrayCreation)) {
      varDecls.addLast(new ArrayDeclaration(
          declNode instanceof GlobalStatement, declNode));

    } else {
      varDecls.addLast(new Declaration(
          declNode instanceof GlobalStatement, declNode));
    }
  }

  public static boolean isInSameBlock(Statement block, ASTNode oldNode,
      ASTNode newNode) {
    if (block instanceof IfStatement) {
      IfStatement ifStatement = (IfStatement) block;
      Statement oldBlock = getBlock(ifStatement, oldNode);
      Statement newBlock = getBlock(ifStatement, newNode);
      if (oldBlock != null && oldBlock == newBlock) {
        return isInSameBlock(newBlock, oldNode, newNode);
      } else {
        return false;
      }
    }
    return true;
  }

  private static Statement getBlock(IfStatement ifStatement, ASTNode node) {
    Statement falseStatement = ifStatement.getFalseStatement();
    Statement trueStatement = ifStatement.getTrueStatement();
    if (trueStatement != null
        && trueStatement.sourceStart() <= node.sourceStart()
        && trueStatement.sourceEnd() >= node.sourceEnd()) {
      return trueStatement;
    } else if (falseStatement != null
        && falseStatement.sourceStart() <= node.sourceStart()
        && falseStatement.sourceEnd() >= node.sourceEnd()) {
      return falseStatement;
    }
    return null;
  }

  public String toString() {
    StringBuilder buf = new StringBuilder("Variable Declarations (") //$NON-NLS-1$
        .append(context).append("): \n\n"); //$NON-NLS-1$
    Iterator<String> i = decls.keySet().iterator();
    while (i.hasNext()) {
      String varName = i.next();
      buf.append(varName).append(" => { \n\n"); //$NON-NLS-1$
      LinkedList<Declaration> varDecls = decls.get(varName);
      if (varDecls != null) {
        for (Declaration declNode : varDecls) {
          buf.append(declNode.toString()).append(", \n\n"); //$NON-NLS-1$
        }
      }
      buf.append("}, \n\n"); //$NON-NLS-1$
    }
    return buf.toString();
  }
}
TOP

Related Classes of org.eclipse.php.internal.core.typeinference.DeclarationScope

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.