1package org.chromium.devtools.jsdoc.checks;
2
3import com.google.common.base.Preconditions;
4import com.google.javascript.rhino.JSTypeExpression;
5import com.google.javascript.rhino.Node;
6import com.google.javascript.rhino.Token;
7
8import java.util.ArrayList;
9import java.util.Collections;
10import java.util.List;
11
12public class AstUtil {
13
14    private static final String PROTOTYPE_SUFFIX = ".prototype";
15
16    static Node parentOfType(Node node, int tokenType) {
17        Node parent = node.getParent();
18        return (parent == null || parent.getType() != tokenType) ? null : parent;
19    }
20
21    /**
22     * Based on NodeUtil#getFunctionNameNode(Node).
23     */
24    static Node getFunctionNameNode(Node node) {
25        Preconditions.checkState(node.isFunction());
26
27        Node parent = node.getParent();
28        if (parent != null) {
29            switch (parent.getType()) {
30            case Token.NAME:
31                // var name = function() ...
32                // var name2 = function name1() ...
33                return parent;
34            // FIXME: Enable the setter and getter checks.
35            // case Token.SETTER_DEF:
36            // case Token.GETTER_DEF:
37            case Token.STRING_KEY:
38                return parent;
39            case Token.NUMBER:
40                return parent;
41            case Token.ASSIGN:
42                int nameType = parent.getFirstChild().getType();
43                // We only consider these types of name nodes as acceptable.
44                return nameType == Token.NAME || nameType == Token.GETPROP
45                    ? parent.getFirstChild()
46                    : null;
47            case Token.VAR:
48                return parent.getFirstChild();
49            default:
50                Node funNameNode = node.getFirstChild();
51                // Don't return the name node for anonymous functions
52                return funNameNode.getString().isEmpty() ? null : funNameNode;
53            }
54        }
55
56        return null;
57    }
58
59    static String getTypeNameFromPrototype(String value) {
60        return value.substring(0, value.length() - PROTOTYPE_SUFFIX.length());
61    }
62
63    static boolean isPrototypeName(String typeName) {
64        return typeName.endsWith(PROTOTYPE_SUFFIX);
65    }
66
67    static Node getAssignedTypeNameNode(Node assignment) {
68        Preconditions.checkState(assignment.isAssign() || assignment.isVar());
69        Node typeNameNode = assignment.getFirstChild();
70        if (typeNameNode.getType() != Token.GETPROP && typeNameNode.getType() != Token.NAME) {
71            return null;
72        }
73        return typeNameNode;
74    }
75
76    static List<Node> getArguments(Node functionCall) {
77        int childCount = functionCall.getChildCount();
78        if (childCount == 1) {
79            return Collections.emptyList();
80        }
81        List<Node> arguments = new ArrayList<>(childCount - 1);
82        for (int i = 1; i < childCount; ++i) {
83            arguments.add(functionCall.getChildAtIndex(i));
84        }
85        return arguments;
86    }
87
88    static String getAnnotationTypeString(JSTypeExpression expression) {
89        return expression.getRoot().getFirstChild().getString();
90    }
91
92    private AstUtil() {}
93}
94