Commit 3d33f02d authored by apavlov@chromium.org's avatar apavlov@chromium.org

DevTools: [JsDocValidator] Check validity of @param and @return annotations

R=vsevik,sergeyv
NOTRY=true

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

git-svn-id: svn://svn.chromium.org/blink/trunk@175579 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent aae8e397
0598e75d3091c10e85700cb50eb739a7f22ddd81b11d3aee02c7caa3d3185e1d src 2b7a3211b34c415d5dd8b0fe6e4cb9e3b46365de62c11059e600059a4bf2f864 src
7d43e120a3d108835b5374a0945fcc3d3d9ad719744f5e736985d14d8eede534 jsdoc-validator.jar 8690d7b1e6486f73ee34ff076af215901e944d17293dc9f039d014d2f94b5804 jsdoc-validator.jar
...@@ -17,7 +17,10 @@ import java.util.regex.Pattern; ...@@ -17,7 +17,10 @@ import java.util.regex.Pattern;
public final class MethodAnnotationChecker extends ContextTrackingChecker { public final class MethodAnnotationChecker extends ContextTrackingChecker {
private static final Pattern PARAM_PATTERN = private static final Pattern PARAM_PATTERN =
Pattern.compile("@param\\s+\\{.+\\}\\s+([^\\s]+)(?:[^}]*)$", Pattern.MULTILINE); Pattern.compile("@param\\s+(\\{.+\\}\\s+)?([^\\s]+).*$", Pattern.MULTILINE);
private static final Pattern INVALID_RETURN_PATTERN =
Pattern.compile("@return(?:s.*|\\s+[^{]*)$", Pattern.MULTILINE);
private final Set<FunctionRecord> valueReturningFunctions = new HashSet<>(); private final Set<FunctionRecord> valueReturningFunctions = new HashSet<>();
private final Set<FunctionRecord> throwingFunctions = new HashSet<>(); private final Set<FunctionRecord> throwingFunctions = new HashSet<>();
...@@ -68,8 +71,14 @@ public final class MethodAnnotationChecker extends ContextTrackingChecker { ...@@ -68,8 +71,14 @@ public final class MethodAnnotationChecker extends ContextTrackingChecker {
String jsDoc = getContext().getNodeText(jsDocNode); String jsDoc = getContext().getNodeText(jsDocNode);
Matcher m = PARAM_PATTERN.matcher(jsDoc); Matcher m = PARAM_PATTERN.matcher(jsDoc);
while (m.find()) { while (m.find()) {
String jsDocParam = m.group(1); String paramType = m.group(1);
paramNames.remove(jsDocParam); if (paramType == null) {
getContext().reportErrorInNode(jsDocNode, m.start(2), String.format(
"Invalid @param annotation found -"
+ " should be \"@param {<type>} paramName\""));
} else {
paramNames.remove(m.group(2));
}
} }
return paramNames.toArray(new String[paramNames.size()]); return paramNames.toArray(new String[paramNames.size()]);
} }
...@@ -130,13 +139,14 @@ public final class MethodAnnotationChecker extends ContextTrackingChecker { ...@@ -130,13 +139,14 @@ public final class MethodAnnotationChecker extends ContextTrackingChecker {
boolean isInterfaceFunction = boolean isInterfaceFunction =
function.enclosingType != null && function.enclosingType.isInterface; function.enclosingType != null && function.enclosingType.isInterface;
int invalidAnnotationIndex = int invalidAnnotationIndex =
invalidReturnsAnnotationIndex(getState().getNodeText(jsDocNode)); invalidReturnAnnotationIndex(getState().getNodeText(jsDocNode));
if (invalidAnnotationIndex != -1) { if (invalidAnnotationIndex != -1) {
String suggestedResolution = (isReturningFunction || isInterfaceFunction) String suggestedResolution = (isReturningFunction || isInterfaceFunction)
? "should be @return instead" ? "should be \"@return {<type>}\""
: "please remove, as function does not return value"; : "please remove, as function does not return value";
getContext().reportErrorInNode(jsDocNode, invalidAnnotationIndex, getContext().reportErrorInNode(jsDocNode, invalidAnnotationIndex,
String.format("invalid @returns annotation found - %s", suggestedResolution)); String.format(
"invalid return type annotation found - %s", suggestedResolution));
return; return;
} }
AstNode functionNameNode = getFunctionNameNode(function.functionNode); AstNode functionNameNode = getFunctionNameNode(function.functionNode);
...@@ -172,8 +182,12 @@ public final class MethodAnnotationChecker extends ContextTrackingChecker { ...@@ -172,8 +182,12 @@ public final class MethodAnnotationChecker extends ContextTrackingChecker {
return nameNode == null ? null : getState().getNodeText(nameNode); return nameNode == null ? null : getState().getNodeText(nameNode);
} }
private static int invalidReturnsAnnotationIndex(String jsDoc) { private static int invalidReturnAnnotationIndex(String jsDoc) {
return jsDoc == null ? -1 : jsDoc.indexOf("@returns"); if (jsDoc == null) {
return -1;
}
Matcher m = INVALID_RETURN_PATTERN.matcher(jsDoc);
return m.find() ? m.start() : -1;
} }
private static AstNode getFunctionNameNode(FunctionNode functionNode) { private static AstNode getFunctionNameNode(FunctionNode functionNode) {
......
...@@ -33,6 +33,24 @@ function badReturnsShouldBeReturnFunc() // ERROR - @returns, should be @return. ...@@ -33,6 +33,24 @@ function badReturnsShouldBeReturnFunc() // ERROR - @returns, should be @return.
return 1; return 1;
} }
/**
* @return number
*/
function badReturnShouldBeTypedFunc() // ERROR - number, not {number}.
{
return 1;
}
/**
* @param number foo
* @param bar
*/
function badParamAnnotationsFunc(foo, bar) // ERROR - @param's should be well-formed
{
return 1;
}
/** /**
* @returns {number} * @returns {number}
*/ */
...@@ -272,6 +290,14 @@ TypeThree.prototype = { ...@@ -272,6 +290,14 @@ TypeThree.prototype = {
return 1; return 1;
}, },
/**
* @returns number
*/
badMethodReturnShouldBeTyped: function() // ERROR - number, not {number}
{
return 1;
},
/** /**
* @returns {number} * @returns {number}
*/ */
...@@ -286,6 +312,15 @@ TypeThree.prototype = { ...@@ -286,6 +312,15 @@ TypeThree.prototype = {
badMethodReturnsShouldBeAbsent: function() // ERROR - @returns, should be absent badMethodReturnsShouldBeAbsent: function() // ERROR - @returns, should be absent
{ {
var foo = 1; var foo = 1;
},
/**
* @param number foo
* @param bar
*/
badMethodParamAnnotations: function(foo, bar) // ERROR - @param's should be well-formed
{
return 1;
} }
} }
......
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