private void handleContinue(Node node) {
    String label = null;
    if (node.hasChildren()) {
      label = node.getFirstChild().getString();
    }
    Node cur;
    Node lastJump;
    // Similar to handBreak's logic with a few minor variation.
    Node parent = node.getParent();
    for (cur = node, lastJump = node;
        !isContinueTarget(cur, parent, label);
        cur = parent, parent = parent.getParent()) {
      if (cur.getType() == Token.TRY && NodeUtil.hasFinally(cur)) {
        if (lastJump == node) {
          createEdge(lastJump, Branch.UNCOND, cur.getLastChild());
        } else {
          finallyMap.put(lastJump, computeFallThrough(cur.getLastChild()));
        }
        lastJump = cur;
      }
      Preconditions.checkState(parent != null, "Cannot find continue target.");
    }
    Node iter = cur;
    if (cur.getChildCount() == 4) {
      iter = cur.getFirstChild().getNext().getNext();
    }

    if (lastJump == node) {
      createEdge(node, Branch.UNCOND, iter);
    } else {
      finallyMap.put(lastJump, iter);
    }
  }
  /**
   * Connects cfgNode to the proper CATCH block if target subtree might throw an exception. If there
   * are FINALLY blocks reached before a CATCH, it will make the corresponding entry in finallyMap.
   */
  private void connectToPossibleExceptionHandler(Node cfgNode, Node target) {
    if (mayThrowException(target) && !exceptionHandler.isEmpty()) {
      Node lastJump = cfgNode;
      for (Node handler : exceptionHandler) {
        if (NodeUtil.isFunction(handler)) {
          return;
        }
        Preconditions.checkState(handler.getType() == Token.TRY);
        Node catchBlock = NodeUtil.getCatchBlock(handler);

        if (!NodeUtil.hasCatchHandler(catchBlock)) { // No catch but a FINALLY.
          if (lastJump == cfgNode) {
            createEdge(cfgNode, Branch.ON_EX, handler.getLastChild());
          } else {
            finallyMap.put(lastJump, handler.getLastChild());
          }
        } else { // Has a catch.
          if (lastJump == cfgNode) {
            createEdge(cfgNode, Branch.ON_EX, catchBlock);
            return;
          } else {
            finallyMap.put(lastJump, catchBlock);
          }
        }
        lastJump = handler;
      }
    }
  }
    /** Replace the current assign with its right hand side. */
    void remove() {
      Node parent = assignNode.getParent();
      if (mayHaveSecondarySideEffects) {
        Node replacement = assignNode.getLastChild().detachFromParent();

        // Aggregate any expressions in GETELEMs.
        for (Node current = assignNode.getFirstChild();
            current.getType() != Token.NAME;
            current = current.getFirstChild()) {
          if (current.getType() == Token.GETELEM) {
            replacement =
                new Node(Token.COMMA, current.getLastChild().detachFromParent(), replacement);
            replacement.copyInformationFrom(current);
          }
        }

        parent.replaceChild(assignNode, replacement);
      } else {
        Node gramps = parent.getParent();
        if (parent.getType() == Token.EXPR_RESULT) {
          gramps.removeChild(parent);
        } else {
          parent.replaceChild(assignNode, assignNode.getLastChild().detachFromParent());
        }
      }
    }
 private JSType getRecordTypeHelper(
     Node n, DeclaredTypeRegistry registry, ImmutableList<String> typeParameters)
     throws UnknownTypeException {
   Map<String, Property> props = new LinkedHashMap<>();
   for (Node propNode = n.getFirstFirstChild(); propNode != null; propNode = propNode.getNext()) {
     boolean isPropDeclared = propNode.getType() == Token.COLON;
     Node propNameNode = isPropDeclared ? propNode.getFirstChild() : propNode;
     String propName = propNameNode.getString();
     if (propName.startsWith("'") || propName.startsWith("\"")) {
       propName = propName.substring(1, propName.length() - 1);
     }
     JSType propType =
         !isPropDeclared
             ? JSType.UNKNOWN
             : getTypeFromCommentHelper(propNode.getLastChild(), registry, typeParameters);
     Property prop;
     if (propType.equals(JSType.UNDEFINED) || isUnionWithUndefined(propNode.getLastChild())) {
       prop = Property.makeOptional(null, propType, propType);
     } else {
       prop = Property.make(propType, propType);
     }
     props.put(propName, prop);
   }
   return JSType.fromObjectType(ObjectType.fromProperties(props));
 }
  private void handleReturn(Node node) {
    Node lastJump = null;
    for (Iterator<Node> iter = exceptionHandler.iterator(); iter.hasNext(); ) {
      Node curHandler = iter.next();
      if (NodeUtil.isFunction(curHandler)) {
        break;
      }
      if (NodeUtil.hasFinally(curHandler)) {
        if (lastJump == null) {
          createEdge(node, Branch.UNCOND, curHandler.getLastChild());
        } else {
          finallyMap.put(lastJump, computeFallThrough(curHandler.getLastChild()));
        }
        lastJump = curHandler;
      }
    }

    if (node.hasChildren()) {
      connectToPossibleExceptionHandler(node, node.getFirstChild());
    }

    if (lastJump == null) {
      createEdge(node, Branch.UNCOND, null);
    } else {
      finallyMap.put(lastJump, null);
    }
  }
Example #6
0
 private void validateObjectPatternComputedPropKey(int type, Node n) {
   validateNodeType(Token.COMPUTED_PROP, n);
   validateChildCount(n);
   validateExpression(n.getFirstChild());
   if (n.getLastChild().isDefaultValue()) {
     validateDefaultValue(type, n.getLastChild());
   } else {
     validateExpression(n.getLastChild());
   }
 }
 Node tryFuseStatements(Node n) {
   if (!n.getParent().isFunction() && canFuseIntoOneStatement(n)) {
     Node start = n.getFirstChild();
     Node end = n.getLastChild();
     Node result = fuseIntoOneStatement(n, start, end);
     fuseExpressionIntoControlFlowStatement(result, n.getLastChild());
     reportCodeChange();
   }
   return n;
 }
Example #8
0
  /**
   * Finds set of all defs in function given (defSites). Adds parameters of function to this set:
   * defSites. Finds all variables that are referenced in the function given (alf.names).
   * windowProps are all global properties available. Closures = alf.names - defSites - windowProps
   *
   * @param n root node of the function who's closures are to be found
   * @return set of closure names
   */
  private Set<String> findClosures(Node n) {
    Set<String> closureVars = null;

    SimpleDefinitionFinder defFinder = new SimpleDefinitionFinder(compiler);
    defFinder.process(externs, n.getLastChild());
    Collection<DefinitionSite> defSites = defFinder.getDefinitionSites();
    Set<String> localDefs = new HashSet<String>();

    for (DefinitionSite site : defSites) {
      if (site.node.getType() == Token.GETPROP) continue;
      String def = site.node.getString();
      if (def.length() > 0) {
        localDefs.add(def);
      }
    }

    // adding params to function as defs
    Node origParamNode = n.getChildAtIndex(1);
    for (int i = 0; i < origParamNode.getChildCount(); i++) {
      String temp = origParamNode.getChildAtIndex(i).getString();
      localDefs.add(temp);
    }

    // System.out.println("\nPrinting LOCAL def sites:" + defs);

    /*SimpleDefinitionFinder defFinder1 = new SimpleDefinitionFinder(compiler);
    defFinder1.process(externs, root);
    Collection<DefinitionSite> defSites1 = defFinder1.getDefinitionSites();
    Set<String> defs1 = new HashSet<String>();

    for(DefinitionSite site1: defSites1){
    	if (site1.node.getType() == Token.GETPROP) continue;
    	String def = site1.node.getString();
    	if (def.length() > 0){
    		defs1.add(def);
    	}
    }
    System.out.println("\nPrinting Global def sites:" + defs1);*/

    AllNamesFinder alf = new AllNamesFinder(compiler);
    NodeTraversal.traverse(compiler, n.getLastChild(), alf);

    // System.out.println("all names: " + alf.names);

    closureVars = alf.names;

    closureVars.removeAll(localDefs);
    closureVars.removeAll(Props.windowProps);

    closureVars.remove(
        "this"); // since 'this' is later modified to $$_self we don't need to consider this as
    // closure

    return closureVars;
  }
Example #9
0
 public void validateRoot(Node n) {
   validateNodeType(Token.BLOCK, n);
   validateIsSynthetic(n);
   validateChildCount(n, 2);
   validateCodeRoot(n.getFirstChild());
   validateCodeRoot(n.getLastChild());
 }
  private void addToDefinePropertiesObject(ClassDeclarationMetadata metadata, Node member) {
    Node obj =
        member.isStaticMember()
            ? metadata.definePropertiesObjForClass
            : metadata.definePropertiesObjForPrototype;
    Node prop = NodeUtil.getFirstPropMatchingKey(obj, member.getString());
    if (prop == null) {
      prop =
          IR.objectlit(
              IR.stringKey("configurable", IR.trueNode()),
              IR.stringKey("enumerable", IR.trueNode()));
      obj.addChildToBack(IR.stringKey(member.getString(), prop));
    }

    Node function = member.getLastChild();
    JSDocInfoBuilder info = JSDocInfoBuilder.maybeCopyFrom(NodeUtil.getBestJSDocInfo(function));

    info.recordThisType(
        new JSTypeExpression(
            new Node(Token.BANG, IR.string(metadata.fullClassName)), member.getSourceFileName()));
    Node stringKey =
        IR.stringKey(member.isGetterDef() ? "get" : "set", function.detachFromParent());
    stringKey.setJSDocInfo(info.build());
    prop.addChildToBack(stringKey);
    prop.useSourceInfoIfMissingFromForTree(member);
  }
  /** Add an @this annotation to all functions in the objLit. */
  private void addTypesToFunctions(Node objLit, String thisType) {
    Preconditions.checkState(objLit.isObjectLit());
    for (Node keyNode : objLit.children()) {
      Node value = keyNode.getLastChild();
      if (value != null && value.isFunction()) {
        JSDocInfoBuilder fnDoc = JSDocInfoBuilder.maybeCopyFrom(keyNode.getJSDocInfo());
        fnDoc.recordThisType(
            new JSTypeExpression(new Node(Token.BANG, IR.string(thisType)), VIRTUAL_FILE));
        keyNode.setJSDocInfo(fnDoc.build());
      }
    }

    // Add @this and @return to default property values.
    for (MemberDefinition property : extractProperties(objLit)) {
      if (!property.value.isObjectLit()) {
        continue;
      }
      if (hasShorthandAssignment(property.value)) {
        compiler.report(JSError.make(property.value, POLYMER_SHORTHAND_NOT_SUPPORTED));
        return;
      }

      Node defaultValue = NodeUtil.getFirstPropMatchingKey(property.value, "value");
      if (defaultValue == null || !defaultValue.isFunction()) {
        continue;
      }
      Node defaultValueKey = defaultValue.getParent();
      JSDocInfoBuilder fnDoc = JSDocInfoBuilder.maybeCopyFrom(defaultValueKey.getJSDocInfo());
      fnDoc.recordThisType(
          new JSTypeExpression(new Node(Token.BANG, IR.string(thisType)), VIRTUAL_FILE));
      fnDoc.recordReturnType(getTypeFromProperty(property));
      defaultValueKey.setJSDocInfo(fnDoc.build());
    }
  }
  /**
   * Removes unreferenced arguments from a function declaration and when possible the function's
   * callSites.
   *
   * @param fnScope The scope inside the function
   */
  private void removeUnreferencedFunctionArgs(Scope fnScope) {
    // TODO(johnlenz): Update type registry for function signature changes.

    Node function = fnScope.getRootNode();

    Preconditions.checkState(function.getType() == Token.FUNCTION);
    if (NodeUtil.isGetOrSetKey(function.getParent())) {
      // The parameters object literal setters can not be removed.
      return;
    }

    Node argList = getFunctionArgList(function);
    boolean modifyCallers = modifyCallSites && callSiteOptimizer.canModifyCallers(function);
    if (!modifyCallers) {
      // Strip unreferenced args off the end of the function declaration.
      Node lastArg;
      while ((lastArg = argList.getLastChild()) != null) {
        Var var = fnScope.getVar(lastArg.getString());
        if (!referenced.contains(var)) {
          Preconditions.checkNotNull(var == null);
          argList.removeChild(lastArg);
          compiler.reportCodeChange();
        } else {
          break;
        }
      }
    } else {
      callSiteOptimizer.optimize(fnScope, referenced);
    }
  }
  protected void testExternChanges(String extern, String input, String expectedExtern) {
    Compiler compiler = createCompiler();
    CompilerOptions options = getOptions();
    compiler.init(
        ImmutableList.of(SourceFile.fromCode("extern", extern)),
        ImmutableList.of(SourceFile.fromCode("input", input)),
        options);
    compiler.parseInputs();
    assertFalse(compiler.hasErrors());

    Node externsAndJs = compiler.getRoot();
    Node root = externsAndJs.getLastChild();

    Node externs = externsAndJs.getFirstChild();

    Node expected = compiler.parseTestCode(expectedExtern);
    assertFalse(compiler.hasErrors());

    (getProcessor(compiler)).process(externs, root);

    String externsCode = compiler.toSource(externs);
    String expectedCode = compiler.toSource(expected);

    assertEquals(expectedCode, externsCode);
  }
  /**
   * Replaces a GETPROP a.b.c with a NAME a$b$c.
   *
   * @param alias A flattened prefix name (e.g. "a$b")
   * @param n The GETPROP node corresponding to the original name (e.g. "a.b")
   * @param parent {@code n}'s parent
   * @param originalName String version of the property name.
   */
  private void flattenNameRef(String alias, Node n, Node parent, String originalName) {
    Preconditions.checkArgument(
        n.isGetProp(), "Expected GETPROP, found %s. Node: %s", Token.name(n.getType()), n);

    // BEFORE:
    //   getprop
    //     getprop
    //       name a
    //       string b
    //     string c
    // AFTER:
    //   name a$b$c
    Node ref = NodeUtil.newName(compiler, alias, n, originalName);
    NodeUtil.copyNameAnnotations(n.getLastChild(), ref);
    if (parent.isCall() && n == parent.getFirstChild()) {
      // The node was a call target, we are deliberately flatten these as
      // we node the "this" isn't provided by the namespace. Mark it as such:
      parent.putBooleanProp(Node.FREE_CALL, true);
    }

    TypeI type = n.getTypeI();
    if (type != null) {
      ref.setTypeI(type);
    }

    parent.replaceChild(n, ref);
    compiler.reportCodeChange();
  }
 private boolean isFusableControlStatement(Node n) {
   switch (n.getToken()) {
     case IF:
     case THROW:
     case SWITCH:
     case EXPR_RESULT:
       return true;
     case RETURN:
       // We don't want to add a new return value.
       return n.hasChildren();
     case FOR:
       if (NodeUtil.isForIn(n)) {
         // Avoid cases where we have for(var x = foo() in a) { ....
         return !mayHaveSideEffects(n.getFirstChild());
       } else {
         // Avoid cases where we have for(var x;_;_) { ....
         return !n.getFirstChild().isVar();
       }
     case LABEL:
       return isFusableControlStatement(n.getLastChild());
     case BLOCK:
       return !n.isSyntheticBlock() && isFusableControlStatement(n.getFirstChild());
     default:
       break;
   }
   return false;
 }
  /**
   * Prepare an template AST to use when performing matches.
   *
   * @param templateFunctionNode The template declaration function to extract the template AST from.
   * @return The first node of the template AST sequence to use when matching.
   */
  private Node initTemplate(Node templateFunctionNode) {
    Node prepped = templateFunctionNode.cloneTree();
    prepTemplatePlaceholders(prepped);

    Node body = prepped.getLastChild();
    Node startNode;
    if (body.hasOneChild() && body.getFirstChild().isExprResult()) {
      // When matching an expression, don't require it to be a complete
      // statement.
      startNode = body.getFirstFirstChild();
    } else {
      startNode = body.getFirstChild();
    }

    for (int i = 0; i < templateLocals.size(); i++) {
      // reserve space in the locals array.
      this.localVarMatches.add(null);
    }
    for (int i = 0; i < templateParams.size(); i++) {
      // reserve space in the params array.
      this.paramNodeMatches.add(null);
    }

    return startNode;
  }
 public void testJSDocAttachment18() {
   Node fn =
       parse("function f() { " + "  var x = /** @type {string} */ (y);" + "};").getFirstChild();
   assertEquals(Token.FUNCTION, fn.getType());
   Node cast = fn.getLastChild().getFirstChild().getFirstChild().getFirstChild();
   assertEquals(Token.CAST, cast.getType());
 }
Example #18
0
 private void validateFunctionStatement(Node n) {
   validateNodeType(Token.FUNCTION, n);
   validateChildCount(n);
   validateName(n.getFirstChild());
   validateParameters(n.getChildAtIndex(1));
   validateBlock(n.getLastChild());
 }
Example #19
0
 private void validateTrinaryOp(Node n) {
   validateChildCount(n);
   Node first = n.getFirstChild();
   validateExpression(first);
   validateExpression(first.getNext());
   validateExpression(n.getLastChild());
 }
  private static void fuseExpressionIntoControlFlowStatement(Node before, Node control) {
    Preconditions.checkArgument(before.isExprResult(), "before must be expression result");

    // Now we are just left with two statements. The comma tree of the first
    // n - 1 statements (which can be used in an expression) and the last
    // statement. We perform specific fusion based on the last statement's type.
    switch (control.getToken()) {
      case IF:
      case RETURN:
      case THROW:
      case SWITCH:
      case EXPR_RESULT:
        before.getParent().removeChild(before);
        fuseExpressionIntoFirstChild(before.removeFirstChild(), control);
        return;
      case FOR:
        before.getParent().removeChild(before);
        if (NodeUtil.isForIn(control)) {
          fuseExpressionIntoSecondChild(before.removeFirstChild(), control);
        } else {
          fuseExpressionIntoFirstChild(before.removeFirstChild(), control);
        }
        return;
      case LABEL:
        fuseExpressionIntoControlFlowStatement(before, control.getLastChild());
        return;
      case BLOCK:
        fuseExpressionIntoControlFlowStatement(before, control.getFirstChild());
        return;
      default:
        throw new IllegalStateException("Statement fusion missing.");
    }
  }
  @Override
  public void visit(NodeTraversal t, Node n, Node parent) {
    // Verify the source file is annotated.
    if (doSanityChecks && sourceFile != null) {
      Preconditions.checkState(sourceFile.equals(n.getProp(Node.SOURCENAME_PROP)));
    }

    // Annotate the original name.
    switch (n.getType()) {
      case Token.GETPROP:
        Node propNode = n.getLastChild();
        setOriginalName(n, propNode.getString());
        break;

      case Token.FUNCTION:
        String functionName = NodeUtil.getNearestFunctionName(n);
        if (functionName != null) {
          setOriginalName(n, functionName);
        }
        break;

      case Token.NAME:
        setOriginalName(n, n.getString());
        break;

      case Token.OBJECTLIT:
        for (Node key = n.getFirstChild(); key != null; key = key.getNext()) {
          // We only want keys were unquoted.
          if (!key.isQuotedString()) {
            setOriginalName(key, key.getString());
          }
        }
        break;
    }
  }
Example #22
0
 private void validateForOf(Node n) {
   validateNodeType(Token.FOR_OF, n);
   validateChildCount(n);
   validateVarOrAssignmentTarget(n.getFirstChild());
   validateExpression(n.getChildAtIndex(1));
   validateBlock(n.getLastChild());
 }
    /**
     * Rename or remove labels.
     *
     * @param node The label node.
     * @param parent The parent of the label node.
     */
    private void visitLabel(Node node, Node parent) {
      Node nameNode = node.getFirstChild();
      Preconditions.checkState(nameNode != null);
      String name = nameNode.getString();
      LabelInfo li = getLabelInfo(name);
      // This is a label...
      if (li.referenced || !removeUnused) {
        String newName = getNameForId(li.id);
        if (!name.equals(newName)) {
          // ... and it is used, give it the short name.
          nameNode.setString(newName);
          compiler.reportCodeChange();
        }
      } else {
        // ... and it is not referenced, just remove it.
        Node newChild = node.getLastChild();
        node.removeChild(newChild);
        parent.replaceChild(node, newChild);
        if (newChild.isBlock()) {
          NodeUtil.tryMergeBlock(newChild);
        }
        compiler.reportCodeChange();
      }

      // Remove the label from the current stack of labels.
      namespaceStack.peek().renameMap.remove(name);
    }
  private void addExportMethod(
      Map<String, GenerateNodeContext> exports, String export, GenerateNodeContext context) {
    CodingConvention convention = compiler.getCodingConvention();

    // Emit the proper CALL expression.
    // This is an optimization to avoid exporting everything as a symbol
    // because exporting a property is significantly simpler/faster.
    // Only export the property if the parent is being exported or
    // if the parent is "prototype" and the grandparent is being exported.
    String parent = null;
    String grandparent = null;

    Node node = context.getNode().getFirstChild();
    if (node.isGetProp()) {
      Node parentNode = node.getFirstChild();
      parent = parentNode.getQualifiedName();
      if (parentNode.isGetProp()
          && parentNode.getLastChild().getString().equals(PROTOTYPE_PROPERTY)) {
        grandparent = parentNode.getFirstChild().getQualifiedName();
      }
    }

    boolean useExportSymbol = true;
    if (grandparent != null && exports.containsKey(grandparent)) {
      // grandparent is only set for properties exported off a prototype obj.
      useExportSymbol = false;
    } else if (parent != null && exports.containsKey(parent)) {
      useExportSymbol = false;
    }

    Node call;
    if (useExportSymbol) {
      // exportSymbol(publicPath, object);
      call =
          IR.call(
              NodeUtil.newQualifiedNameNode(
                  convention, exportSymbolFunction, context.getNode(), export),
              IR.string(export),
              NodeUtil.newQualifiedNameNode(convention, export, context.getNode(), export));
    } else {
      // exportProperty(object, publicName, symbol);
      String property = getPropertyName(node);
      call =
          IR.call(
              NodeUtil.newQualifiedNameNode(
                  convention, exportPropertyFunction, context.getNode(), exportPropertyFunction),
              NodeUtil.newQualifiedNameNode(
                  convention, parent, context.getNode(), exportPropertyFunction),
              IR.string(property),
              NodeUtil.newQualifiedNameNode(
                  convention, export, context.getNode(), exportPropertyFunction));
    }

    Node expression = IR.exprResult(call);
    annotate(expression);

    addStatement(context, expression);

    compiler.reportCodeChange();
  }
Example #25
0
  private void validateTry(Node n) {
    validateNodeType(Token.TRY, n);
    validateChildCountIn(n, 2, 3);
    validateBlock(n.getFirstChild());

    boolean seenCatchOrFinally = false;

    // Validate catch
    Node catches = n.getChildAtIndex(1);
    validateNodeType(Token.BLOCK, catches);
    validateMaximumChildCount(catches, 1);
    if (catches.hasChildren()) {
      validateCatch(catches.getFirstChild());
      seenCatchOrFinally = true;
    }

    // Validate finally
    if (n.getChildCount() == 3) {
      validateBlock(n.getLastChild());
      seenCatchOrFinally = true;
    }

    if (!seenCatchOrFinally) {
      violation("Missing catch or finally for try statement.", n);
    }
  }
    /** If this is an assign to a variable or its property, return it. Otherwise, return null. */
    static Assign maybeCreateAssign(Node assignNode) {
      Preconditions.checkState(NodeUtil.isAssignmentOp(assignNode));

      // Skip one level of GETPROPs or GETELEMs.
      //
      // Don't skip more than one level, because then we get into
      // situations where assigns to properties of properties will always
      // trigger side-effects, and the variable they're on cannot be removed.
      boolean isPropAssign = false;
      Node current = assignNode.getFirstChild();
      if (NodeUtil.isGet(current)) {
        current = current.getFirstChild();
        isPropAssign = true;

        if (current.getType() == Token.GETPROP
            && current.getLastChild().getString().equals("prototype")) {
          // Prototype properties sets should be considered like normal
          // property sets.
          current = current.getFirstChild();
        }
      }

      if (current.getType() == Token.NAME) {
        return new Assign(assignNode, current, isPropAssign);
      }
      return null;
    }
  /**
   * Inline a function that fulfills the requirements of canInlineReferenceDirectly into the call
   * site, replacing only the CALL node.
   */
  private Node inlineReturnValue(Node callNode, Node fnNode) {
    Node block = fnNode.getLastChild();
    Node callParentNode = callNode.getParent();

    // NOTE: As the normalize pass guarantees globals aren't being
    // shadowed and an expression can't introduce new names, there is
    // no need to check for conflicts.

    // Create an argName -> expression map, checking for side effects.
    Map<String, Node> argMap =
        FunctionArgumentInjector.getFunctionCallParameterMap(
            fnNode, callNode, this.safeNameIdSupplier);

    Node newExpression;
    if (!block.hasChildren()) {
      Node srcLocation = block;
      newExpression = NodeUtil.newUndefinedNode(srcLocation);
    } else {
      Node returnNode = block.getFirstChild();
      Preconditions.checkArgument(returnNode.getType() == Token.RETURN);

      // Clone the return node first.
      Node safeReturnNode = returnNode.cloneTree();
      Node inlineResult = FunctionArgumentInjector.inject(safeReturnNode, null, argMap);
      Preconditions.checkArgument(safeReturnNode == inlineResult);
      newExpression = safeReturnNode.removeFirstChild();
    }

    callParentNode.replaceChild(callNode, newExpression);
    return newExpression;
  }
 @Override
 public void visit(NodeTraversal t, Node n, Node parent) {
   switch (n.getType()) {
     case Token.OBJECTLIT:
       for (Node child : n.children()) {
         if (child.isComputedProp()) {
           visitObjectWithComputedProperty(n, parent);
           break;
         }
       }
       break;
     case Token.MEMBER_DEF:
       if (parent.isObjectLit()) {
         visitMemberDefInObjectLit(n, parent);
       }
       break;
     case Token.FOR_OF:
       visitForOf(n, parent);
       break;
     case Token.SUPER:
       visitSuper(n, parent);
       break;
     case Token.STRING_KEY:
       visitStringKey(n);
       break;
     case Token.CLASS:
       for (Node member = n.getLastChild().getFirstChild();
           member != null;
           member = member.getNext()) {
         if (member.isGetterDef()
             || member.isSetterDef()
             || member.getBooleanProp(Node.COMPUTED_PROP_GETTER)
             || member.getBooleanProp(Node.COMPUTED_PROP_SETTER)) {
           cannotConvert(member, "getters or setters in class definitions");
           return;
         }
       }
       visitClass(n, parent);
       break;
     case Token.ARRAYLIT:
     case Token.NEW:
     case Token.CALL:
       for (Node child : n.children()) {
         if (child.isSpread()) {
           visitArrayLitOrCallWithSpread(n, parent);
           break;
         }
       }
       break;
     case Token.TEMPLATELIT:
       Es6TemplateLiterals.visitTemplateLiteral(t, n);
       break;
     case Token.ARRAY_PATTERN:
       visitArrayPattern(t, n, parent);
       break;
     case Token.OBJECT_PATTERN:
       visitObjectPattern(t, n, parent);
       break;
   }
 }
Example #29
0
 private void validateGetProp(Node n) {
   validateNodeType(Token.GETPROP, n);
   validateChildCount(n);
   validateExpression(n.getFirstChild());
   Node prop = n.getLastChild();
   validateNodeType(Token.STRING, prop);
   validateNonEmptyString(prop);
 }
 /**
  * Gets whether a name ends with a field name that should be stripped. For example, this
  * function would return true when passed "this.logger" or "a.b.c.myLogger" if "logger" is a
  * strip name.
  *
  * @param n A node (typically a GETPROP node)
  * @return Whether the name ends with a field name that should be stripped
  */
 boolean nameEndsWithFieldNameToStrip(@Nullable Node n) {
   if (n != null && n.getType() == Token.GETPROP) {
     Node propNode = n.getLastChild();
     return propNode != null
         && propNode.getType() == Token.STRING
         && isStripName(propNode.getString());
   }
   return false;
 }