Commit e596caec authored by apavlov@chromium.org's avatar apavlov@chromium.org

DevTools: [JsDocValidator] Handle types declared as top-level vars

This patch allows the validator checks to handle types declared as
/** @constructor */ var MyType = function() {}

R=pfeldman, sergeyv

Review URL: https://codereview.chromium.org/218993012

git-svn-id: svn://svn.chromium.org/blink/trunk@170555 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent ddfc31a2
897c41ac961d3b29241cbc669a7b8de9bab29576011ba14d5221074236ef6eaf src 2ab8423657e11313213f1650bc22a361b67ef9e17eb532c4c3ec3b1041a22654 src
c2d110cf773c37260c650b98086345d5a5796baec0552758d84d403c86306edb jsdoc-validator.jar c763ce82987ebe06894c8b99bbc5db0ce7cd6e4882b6fddf2ced12051d61eaa6 jsdoc-validator.jar
...@@ -6,17 +6,15 @@ import com.google.javascript.rhino.head.ast.AstNode; ...@@ -6,17 +6,15 @@ import com.google.javascript.rhino.head.ast.AstNode;
import com.google.javascript.rhino.head.ast.Comment; import com.google.javascript.rhino.head.ast.Comment;
import com.google.javascript.rhino.head.ast.FunctionNode; import com.google.javascript.rhino.head.ast.FunctionNode;
import com.google.javascript.rhino.head.ast.ObjectProperty; import com.google.javascript.rhino.head.ast.ObjectProperty;
import com.google.javascript.rhino.head.ast.VariableInitializer;
public class AstUtil { public class AstUtil {
private static final String PROTOTYPE_SUFFIX = ".prototype"; private static final String PROTOTYPE_SUFFIX = ".prototype";
static boolean hasParentOfType(AstNode node, int tokenType) { static AstNode parentOfType(AstNode node, int tokenType) {
AstNode parent = node.getParent(); AstNode parent = node.getParent();
if (parent == null) { return (parent == null || parent.getType() != tokenType) ? null : parent;
return false;
}
return parent.getType() == tokenType;
} }
static AstNode getFunctionNameNode(FunctionNode functionNode) { static AstNode getFunctionNameNode(FunctionNode functionNode) {
...@@ -25,16 +23,24 @@ public class AstUtil { ...@@ -25,16 +23,24 @@ public class AstUtil {
return nameNode; return nameNode;
} }
if (AstUtil.hasParentOfType(functionNode, Token.COLON)) { AstNode parentNode = functionNode.getParent();
return ((ObjectProperty) functionNode.getParent()).getLeft(); if (parentNode == null) {
return null;
} }
if (AstUtil.hasParentOfType(functionNode, Token.ASSIGN)) { switch (parentNode.getType()) {
Assignment assignment = (Assignment) functionNode.getParent(); case Token.COLON:
return ((ObjectProperty) parentNode).getLeft();
case Token.ASSIGN:
Assignment assignment = (Assignment) parentNode;
if (assignment.getRight() == functionNode) { if (assignment.getRight() == functionNode) {
return assignment.getLeft(); return assignment.getLeft();
} }
break;
case Token.VAR:
return ((VariableInitializer) parentNode).getTarget();
} }
return null; return null;
} }
...@@ -69,22 +75,24 @@ public class AstUtil { ...@@ -69,22 +75,24 @@ public class AstUtil {
} }
// reader.onloadend = function() {...} // reader.onloadend = function() {...}
if (hasParentOfType(functionNode, Token.ASSIGN)) { AstNode parentNode = functionNode.getParent();
Assignment assignment = (Assignment) functionNode.getParent(); if (parentNode == null) {
if (assignment.getRight() == functionNode) { return null;
jsDocNode = assignment.getJsDocNode();
if (jsDocNode != null) {
return jsDocNode;
}
}
} }
if (hasParentOfType(functionNode, Token.COLON)) { switch (parentNode.getType()) {
jsDocNode = ((ObjectProperty) functionNode.getParent()).getLeft().getJsDocNode(); case Token.COLON:
if (jsDocNode != null) { return ((ObjectProperty) parentNode).getLeft().getJsDocNode();
return jsDocNode; case Token.ASSIGN:
Assignment assignment = (Assignment) parentNode;
if (assignment.getRight() == functionNode) {
return assignment.getJsDocNode();
} }
break;
case Token.VAR:
return parentNode.getParent().getJsDocNode();
} }
return null; return null;
} }
......
...@@ -195,7 +195,9 @@ public class ContextTrackingValidationCheck extends ValidationCheck { ...@@ -195,7 +195,9 @@ public class ContextTrackingValidationCheck extends ValidationCheck {
List<InheritanceEntry> result = new ArrayList<>(2); List<InheritanceEntry> result = new ArrayList<>(2);
Matcher matcher = EXTENDS_PATTERN.matcher(getNodeText(jsDocNode)); Matcher matcher = EXTENDS_PATTERN.matcher(getNodeText(jsDocNode));
while (matcher.find()) { while (matcher.find()) {
result.add(new InheritanceEntry(matcher.group(1), jsDocNode, matcher.start(1))); String fullSuperType = matcher.group(1);
result.add(new InheritanceEntry(
fullSuperType.replaceFirst("\\.<.+>", ""), jsDocNode, matcher.start(1)));
} }
return result; return result;
......
...@@ -30,7 +30,7 @@ public final class ReturnAnnotationChecker extends ContextTrackingChecker { ...@@ -30,7 +30,7 @@ public final class ReturnAnnotationChecker extends ContextTrackingChecker {
} }
private void handleReturn(ReturnStatement node) { private void handleReturn(ReturnStatement node) {
if (node.getReturnValue() == null || AstUtil.hasParentOfType(node, Token.ASSIGN)) { if (node.getReturnValue() == null || AstUtil.parentOfType(node, Token.ASSIGN) != null) {
return; return;
} }
...@@ -137,8 +137,9 @@ public final class ReturnAnnotationChecker extends ContextTrackingChecker { ...@@ -137,8 +137,9 @@ public final class ReturnAnnotationChecker extends ContextTrackingChecker {
return nameNode; return nameNode;
} }
if (AstUtil.hasParentOfType(functionNode, Token.COLON)) { ObjectProperty parent = (ObjectProperty) AstUtil.parentOfType(functionNode, Token.COLON);
return ((ObjectProperty) functionNode.getParent()).getLeft(); if (parent != null) {
return parent.getLeft();
} }
// Do not require annotation for assignment-RHS functions. // Do not require annotation for assignment-RHS functions.
return null; return null;
......
...@@ -50,6 +50,14 @@ DerivedNoSuperCall = function() { ...@@ -50,6 +50,14 @@ DerivedNoSuperCall = function() {
DerivedBadSuperCall = function() { DerivedBadSuperCall = function() {
^ ^
/usr/local/google/home/apavlov/dev/blink/src/third_party/WebKit/Source/devtools/scripts/jsdoc-validator/tests/proto.js:121: ERROR - No __proto__ assigned for type BadSetSubclass having @extends
* @extends {Set.<T>}
^
/usr/local/google/home/apavlov/dev/blink/src/third_party/WebKit/Source/devtools/scripts/jsdoc-validator/tests/proto.js:124: ERROR - Type BadSetSubclass extends Set but does not properly invoke its constructor
var BadSetSubclass = function()
^
/usr/local/google/home/apavlov/dev/blink/src/third_party/WebKit/Source/devtools/scripts/jsdoc-validator/tests/return.js:1: ERROR - @return annotation is required for API functions that return value /usr/local/google/home/apavlov/dev/blink/src/third_party/WebKit/Source/devtools/scripts/jsdoc-validator/tests/return.js:1: ERROR - @return annotation is required for API functions that return value
function badFuncNoAnnotation() { function badFuncNoAnnotation() {
^ ^
...@@ -278,4 +286,4 @@ function badFuncAnnotatedButNoReturnValue() // ERROR - no returned value. ...@@ -278,4 +286,4 @@ function badFuncAnnotatedButNoReturnValue() // ERROR - no returned value.
function callbackNotReferencingThisAnnotated() function callbackNotReferencingThisAnnotated()
^ ^
Total errors: 70 Total errors: 72
...@@ -88,3 +88,42 @@ GoodDerived = function() { ...@@ -88,3 +88,42 @@ GoodDerived = function() {
GoodDerived.prototype = { GoodDerived.prototype = {
__proto__: Base.prototype __proto__: Base.prototype
} }
/**
* @constructor
* @template T
*/
var Set = function() {}
Set.prototype = {
add: function(item) {},
remove: function(item) {},
/** @return {boolean} */
contains: function(item) { return true; }
}
/**
* @constructor
* @extends {Set.<T>}
* @template T
*/
var GoodSetSubclass = function()
{
Set.call(this);
}
GoodSetSubclass.prototype = {
__proto__: Set.prototype
}
/**
* @constructor
* @extends {Set.<T>}
* @template T
*/
var BadSetSubclass = function()
{
}
BadSetSubclass.prototype = {
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment