Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / scripts / jsdoc-validator / src / org / chromium / devtools / jsdoc / checks / ContextTrackingValidationCheck.java
1 package org.chromium.devtools.jsdoc.checks;
2
3 import com.google.javascript.rhino.JSDocInfo;
4 import com.google.javascript.rhino.Node;
5 import com.google.javascript.rhino.Token;
6
7 import org.chromium.devtools.jsdoc.ValidationCheck;
8 import org.chromium.devtools.jsdoc.ValidatorContext;
9
10 import java.util.ArrayList;
11 import java.util.List;
12
13 public class ContextTrackingValidationCheck extends ValidationCheck {
14
15     private ContextTrackingState state;
16     private final List<ContextTrackingChecker> clients = new ArrayList<>(5);
17
18     @Override
19     protected void setContext(ValidatorContext context) {
20         super.setContext(context);
21         state = new ContextTrackingState(context);
22         registerClient(new ProtoFollowsExtendsChecker());
23         registerClient(new MethodAnnotationChecker());
24         registerClient(new FunctionReceiverChecker());
25     }
26
27     @Override
28     public void doVisit(Node node) {
29         switch (node.getType()) {
30         case Token.ASSIGN:
31         case Token.VAR:
32             enterAssignOrVarNode(node);
33             break;
34         case Token.FUNCTION:
35             enterFunctionNode(node);
36             break;
37         default:
38             break;
39         }
40
41         enterNode(node);
42     }
43
44     @Override
45     public void didVisit(Node node) {
46         leaveNode(node);
47
48         switch (node.getType()) {
49         case Token.ASSIGN:
50             leaveAssignNode(node);
51             break;
52         case Token.FUNCTION:
53             leaveFunctionNode(node);
54             break;
55         default:
56             break;
57         }
58     }
59
60     public void registerClient(ContextTrackingChecker client) {
61         this.clients.add(client);
62         client.setState(state);
63     }
64
65     private void enterNode(Node node) {
66         for (ContextTrackingChecker client : clients) {
67             client.enterNode(node);
68         }
69     }
70
71     private void leaveNode(Node node) {
72         for (ContextTrackingChecker client : clients) {
73             client.leaveNode(node);
74         }
75     }
76
77     private void enterFunctionNode(Node node) {
78         TypeRecord parentType = state.getCurrentFunctionRecord() == null
79                 ? state.getCurrentTypeRecord()
80                 : null;
81         Node nameNode = AstUtil.getFunctionNameNode(node);
82         String functionName = nameNode == null ? null : state.getNodeText(nameNode);
83         FunctionRecord functionRecord = new FunctionRecord(
84                 node,
85                 functionName,
86                 parentType,
87                 state.getCurrentFunctionRecord());
88         state.pushFunctionRecord(functionRecord);
89         rememberTypeRecordIfNeeded(functionName, functionRecord.info);
90     }
91
92     @SuppressWarnings("unused")
93     private void leaveFunctionNode(Node node) {
94         state.functionRecords.removeLast();
95     }
96
97     private void enterAssignOrVarNode(Node node) {
98         String assignedTypeName = getAssignedTypeName(node);
99         if (assignedTypeName == null) {
100             return;
101         }
102         if (AstUtil.isPrototypeName(assignedTypeName)) {
103             // MyType.prototype = ...
104             String typeName = AstUtil.getTypeNameFromPrototype(assignedTypeName);
105             TypeRecord typeRecord = state.typeRecordsByTypeName.get(typeName);
106             // We should push anything here to maintain a valid current type record.
107             state.pushTypeRecord(typeRecord);
108             state.pushFunctionRecord(null);
109             return;
110         }
111     }
112
113     private void leaveAssignNode(Node assignment) {
114         String assignedTypeName = getAssignedTypeName(assignment);
115         if (assignedTypeName == null) {
116             return;
117         }
118         if (AstUtil.isPrototypeName(assignedTypeName)) {
119             // Remove the current type record when leaving prototype object.
120             state.typeRecords.removeLast();
121             state.functionRecords.removeLast();
122             return;
123         }
124     }
125
126     private String getAssignedTypeName(Node assignment) {
127         Node node = AstUtil.getAssignedTypeNameNode(assignment);
128         return getNodeText(node);
129     }
130
131     private boolean rememberTypeRecordIfNeeded(String typeName, JSDocInfo info) {
132         if (info == null) {
133             return false;
134         }
135         if (typeName == null) {
136             return info.isConstructor() || info.isInterface();
137         }
138         if (!info.isConstructor() && !info.isInterface()) {
139             return false;
140         }
141         TypeRecord record = new TypeRecord(typeName, info);
142         state.typeRecordsByTypeName.put(typeName, record);
143         return true;
144     }
145 }