示例#1
0
  /*
   * (non-Javadoc)
   * @see com.aptana.editor.js.parsing.ast.JSTreeWalker#visit(com.aptana.editor.js.parsing.ast.JSFunctionNode)
   */
  @Override
  public void visit(JSFunctionNode node) {
    List<String> types = new ArrayList<String>();
    JSScope scope = this.getActiveScope(node.getBody().getStartingOffset());
    boolean foundReturnExpression = false;

    // infer return types
    for (JSReturnNode returnValue : node.getReturnNodes()) {
      IParseNode expression = returnValue.getExpression();

      if (!expression.isEmpty()) {
        foundReturnExpression = true;

        types.addAll(this.getTypes(expression, scope));
      }
    }

    // If we couldn't infer a return type and we had a return
    // expression, then have it return Object
    if (foundReturnExpression && types.isEmpty()) {
      types.add(JSTypeConstants.OBJECT_TYPE);
    }

    // build function type, including return values
    String type = JSTypeUtil.toFunctionType(types);
    this.addType(type);
  }
示例#2
0
 /**
  * addType
  *
  * @param type
  */
 protected void addType(String type) {
   if (type != null && type.length() > 0) {
     if (this._types == null) {
       this._types = new ArrayList<String>();
     }
     type = JSTypeUtil.validateTypeName(type);
     if (!this._types.contains(type)) {
       this._types.add(type);
     }
   }
 }
示例#3
0
 /*
  * (non-Javadoc)
  * @see com.aptana.editor.js.parsing.ast.JSTreeWalker#visit(com.aptana.editor.js.parsing.ast.JSArrayNode)
  */
 @Override
 public void visit(JSArrayNode node) {
   if (!node.hasChildren()) {
     this.addType(JSTypeConstants.ARRAY_TYPE);
   } else {
     // TODO: Add all element types?
     // TODO: Create equivalent of "structure" type if element types vary?
     for (String type : this.getTypes(node.getFirstChild())) {
       this.addType(JSTypeUtil.createGenericArrayType(type));
     }
   }
 }
示例#4
0
  /*
   * (non-Javadoc)
   * @see com.aptana.editor.js.parsing.ast.JSTreeWalker#visit(com.aptana.editor.js.parsing.ast.JSGetElementNode)
   */
  @Override
  public void visit(JSGetElementNode node) {
    // TODO: Should check subscript to determine if the type is a Number or
    // a String. If it is a String, then this should behave like get-property
    // assuming we can retrieve a literal string.
    IParseNode lhs = node.getLeftHandSide();

    if (lhs instanceof JSNode) {
      for (String typeName : this.getTypes(lhs)) {
        String typeString = JSTypeUtil.getArrayElementType(typeName);

        if (typeString != null) {
          this.addType(typeString);
        } else {
          this.addType(JSTypeConstants.OBJECT_TYPE);
        }
      }
    }
  }
示例#5
0
  /*
   * (non-Javadoc)
   * @see com.aptana.editor.js.parsing.ast.JSTreeWalker#visit(com.aptana.editor.js.parsing.ast.JSConstructNode)
   */
  @Override
  public void visit(JSConstructNode node) {
    // TODO: Need to handle any property assignments off of "this"
    IParseNode child = node.getExpression();

    if (child instanceof JSNode) {
      List<String> types = this.getTypes(child);
      List<String> returnTypes = new ArrayList<String>();

      for (String typeName : types) {
        if (typeName.startsWith(JSTypeConstants.GENERIC_CLASS_OPEN)) {
          returnTypes.add(JSTypeUtil.getClassType(typeName));
        } else {
          // FIXME If this is a function that returns a type, assume that function is a constructor
          // and we've
          // defined the type as Function<Type>.
          // This is where the properties for that type are going to be hung.
          // That may not be "right". We may want to unwrap the function's return type and use that
          // as the
          // type we're dealing with.
          // in that case, we need to change JSSymbolTypeInferrer#generateType to also unwrap
          // Function<Type>
          // properly.
          returnTypes.add(typeName);
        }
      }

      for (String typeName : returnTypes) {
        Collection<PropertyElement> properties =
            this._queryHelper.getTypeMembers(
                this._index, typeName, JSTypeConstants.PROTOTYPE_PROPERTY);

        if (properties != null) {
          for (PropertyElement property : properties) {
            for (String propertyType : property.getTypeNames()) {
              this.addType(propertyType);
            }
          }
        }
      }
    }
  }
示例#6
0
  /*
   * (non-Javadoc)
   * @see com.aptana.editor.js.parsing.ast.JSTreeWalker#visit(com.aptana.editor.js.parsing.ast.JSInvokeNode)
   */
  @Override
  public void visit(JSInvokeNode node) {
    IParseNode child = node.getExpression();

    if (child instanceof JSNode) {
      // TODO hang the "require" string as a constant somewhere!
      if (child instanceof JSIdentifierNode
          && "require".equals(child.getNameNode().getName())) // $NON-NLS-1$
      {
        // it's a requires!
        JSArgumentsNode args = (JSArgumentsNode) node.getArguments();
        IParseNode[] children = args.getChildren();
        for (IParseNode arg : children) {
          if (arg instanceof JSStringNode) {
            JSStringNode string = (JSStringNode) arg;
            String text = string.getText();
            // strip quotes TODO Use util method to strip quotes!
            if (text.startsWith("'") || text.startsWith("\"")) // $NON-NLS-1$ //$NON-NLS-2$
            {
              text = text.substring(1, text.length() - 1);
            }

            // Handle resolving absolute versus relative module ids!
            URI resolved = _location.resolve(text);
            URI relative = _index.getRelativeDocumentPath(resolved);
            this.addType(relative.getPath() + ".exports"); // $NON-NLS-1$
          }
        }
      }

      List<String> types = this.getTypes(child);

      // NOTE: This is a special case for functions used as a RHS of assignments or as part of a
      // property chain.
      // If the invocation returns undefined, we change that to Object.
      // TODO: As a refinement, we want to check that the function being called is not defined in
      // the current
      // scope
      if (types.isEmpty()) {
        IParseNode parent = node.getParent();

        if (parent != null) {
          switch (parent.getNodeType()) {
            case IJSNodeTypes.ASSIGN:
              if (node.getIndex() == 1) {
                this.addType(JSTypeConstants.OBJECT_TYPE);
              }
              break;

            case IJSNodeTypes.GET_PROPERTY:
              this.addType(JSTypeConstants.OBJECT_TYPE);
              break;

            default:
              break;
          }
        }
      }

      for (String typeName : types) {
        if (JSTypeUtil.isFunctionPrefix(typeName)) {
          List<String> returnTypes = JSTypeUtil.getFunctionSignatureReturnTypeNames(typeName);
          for (String returnTypeName : returnTypes) {
            this.addType(returnTypeName);
          }
        }
      }
    }
  }