Package com.google.dart.engine.utilities.ast

Source Code of com.google.dart.engine.utilities.ast.ScopedNameFinder

/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.utilities.ast;

import com.google.dart.engine.ast.AstNode;
import com.google.dart.engine.ast.Block;
import com.google.dart.engine.ast.CatchClause;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.Declaration;
import com.google.dart.engine.ast.DeclaredIdentifier;
import com.google.dart.engine.ast.FieldDeclaration;
import com.google.dart.engine.ast.ForEachStatement;
import com.google.dart.engine.ast.ForStatement;
import com.google.dart.engine.ast.FormalParameter;
import com.google.dart.engine.ast.FunctionDeclaration;
import com.google.dart.engine.ast.FunctionDeclarationStatement;
import com.google.dart.engine.ast.FunctionExpression;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.NodeList;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.Statement;
import com.google.dart.engine.ast.SwitchMember;
import com.google.dart.engine.ast.TopLevelVariableDeclaration;
import com.google.dart.engine.ast.TypeAlias;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.ast.VariableDeclarationStatement;
import com.google.dart.engine.ast.visitor.GeneralizingAstVisitor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Traverse the AST from initial child node to successive parents, building a collection of local
* variable and parameter names visible to the initial child node. In case of name shadowing, the
* first name seen is the most specific one so names are not redefined.
* <p>
* Completion test code coverage is 95%. The two basic blocks that are not executed cannot be
* executed. They are included for future reference.
*
* @coverage com.google.dart.engine.services.completion
*/
public class ScopedNameFinder extends GeneralizingAstVisitor<Void> {

  private Declaration declarationNode;
  private AstNode immediateChild;
  private Map<String, SimpleIdentifier> locals = new HashMap<String, SimpleIdentifier>();
  private int position;
  private boolean referenceIsWithinLocalFunction;

  public ScopedNameFinder(int position) {
    this.position = position;
  }

  public Declaration getDeclaration() {
    return declarationNode;
  }

  public Map<String, SimpleIdentifier> getLocals() {
    return locals;
  }

  @Override
  public Void visitBlock(Block node) {
    checkStatements(node.getStatements());
    return super.visitBlock(node);
  }

  @Override
  public Void visitCatchClause(CatchClause node) {
    addToScope(node.getExceptionParameter());
    addToScope(node.getStackTraceParameter());
    return super.visitCatchClause(node);
  }

  @Override
  public Void visitConstructorDeclaration(ConstructorDeclaration node) {
    if (immediateChild != node.getParameters()) {
      addParameters(node.getParameters().getParameters());
    }
    declarationNode = node;
    return null;
  }

  @Override
  public Void visitFieldDeclaration(FieldDeclaration node) {
    declarationNode = node;
    return null;
  }

  @Override
  public Void visitForEachStatement(ForEachStatement node) {
    DeclaredIdentifier loopVariable = node.getLoopVariable();
    if (loopVariable != null) {
      addToScope(loopVariable.getIdentifier());
    }
    return super.visitForEachStatement(node);
  }

  @Override
  public Void visitForStatement(ForStatement node) {
    if (immediateChild != node.getVariables() && node.getVariables() != null) {
      addVariables(node.getVariables().getVariables());
    }
    return super.visitForStatement(node);
  }

  @Override
  public Void visitFunctionDeclaration(FunctionDeclaration node) {
    if (!(node.getParent() instanceof FunctionDeclarationStatement)) {
      declarationNode = node;
      return null;
    }
    return super.visitFunctionDeclaration(node);
  }

  @Override
  public Void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
    referenceIsWithinLocalFunction = true;
    return super.visitFunctionDeclarationStatement(node);
  }

  @Override
  public Void visitFunctionExpression(FunctionExpression node) {
    if (node.getParameters() != null && immediateChild != node.getParameters()) {
      addParameters(node.getParameters().getParameters());
    }
    return super.visitFunctionExpression(node);
  }

  @Override
  public Void visitMethodDeclaration(MethodDeclaration node) {
    declarationNode = node;
    if (node.getParameters() == null) {
      return null;
    }
    if (immediateChild != node.getParameters()) {
      addParameters(node.getParameters().getParameters());
    }
    return null;
  }

  @Override
  public Void visitNode(AstNode node) {
    immediateChild = node;
    AstNode parent = node.getParent();
    if (parent != null) {
      parent.accept(this);
    }
    return null;
  }

  @Override
  public Void visitSwitchMember(SwitchMember node) {
    checkStatements(node.getStatements());
    return super.visitSwitchMember(node);
  }

  @Override
  public Void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
    declarationNode = node;
    return null;
  }

  @Override
  public Void visitTypeAlias(TypeAlias node) {
    declarationNode = node; // not reached
    return null;
  }

  private void addParameters(NodeList<FormalParameter> vars) {
    for (FormalParameter var : vars) {
      addToScope(var.getIdentifier());
    }
  }

  private void addToScope(SimpleIdentifier identifier) {
    if (identifier != null && isInRange(identifier)) {
      String name = identifier.getName();
      if (!locals.containsKey(name)) {
        locals.put(name, identifier);
      }
    }
  }

  private void addVariables(NodeList<VariableDeclaration> vars) {
    for (VariableDeclaration var : vars) {
      addToScope(var.getName());
    }
  }

  /**
   * Some statements define names that are visible downstream. There aren't many of these.
   *
   * @param statements the list of statements to check for name definitions
   */
  private void checkStatements(List<Statement> statements) {
    for (Statement stmt : statements) {
      if (stmt == immediateChild) {
        return;
      }
      if (stmt instanceof VariableDeclarationStatement) {
        addVariables(((VariableDeclarationStatement) stmt).getVariables().getVariables());
      } else if (stmt instanceof FunctionDeclarationStatement && !referenceIsWithinLocalFunction) {
        addToScope(((FunctionDeclarationStatement) stmt).getFunctionDeclaration().getName());
      }
    }
  }

  private boolean isInRange(AstNode node) {
    if (position < 0) {
      // if source position is not set then all nodes are in range
      return true; // not reached
    }
    return node.getEnd() < position;
  }

}
TOP

Related Classes of com.google.dart.engine.utilities.ast.ScopedNameFinder

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.