[javascriptlint-commit] SF.net SVN: javascriptlint:[238] trunk
Status: Beta
Brought to you by:
matthiasmiller
From: <mat...@us...> - 2009-03-03 17:03:09
|
Revision: 238 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=238&view=rev Author: matthiasmiller Date: 2009-03-03 17:02:59 +0000 (Tue, 03 Mar 2009) Log Message: ----------- missing_semicolon: implement the missing semicolon warning This is not the most elegant solution, but it requires the least invasive changes to spidermonkey. Modified Paths: -------------- trunk/pyjsl/jsparse.py trunk/pyjsl/lint.py trunk/pyjsl/warnings.py trunk/pyspidermonkey/pyspidermonkey.c trunk/spidermonkey/src/jsparse.c trunk/spidermonkey/src/jsparse.h trunk/test.py trunk/tests/control_comments/declare.js trunk/tests/warnings/missing_semicolon.js trunk/tests/warnings/unreferenced_identifier.js Added Paths: ----------- trunk/tests/warnings/missing_semicolon_for_lambda.js Removed Paths: ------------- trunk/tests/conf/lambda_assign_requires_semicolon.js Modified: trunk/pyjsl/jsparse.py =================================================================== --- trunk/pyjsl/jsparse.py 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/pyjsl/jsparse.py 2009-03-03 17:02:59 UTC (rev 238) @@ -253,6 +253,9 @@ if hasattr(node, 'atom'): print ' '*depth, print 'atom: %s' % node.atom + if node.no_semi: + print ' '*depth, + print '(no semicolon)' print for node in node.kids: _dump_node(node, depth+1) Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/pyjsl/lint.py 2009-03-03 17:02:59 UTC (rev 238) @@ -376,7 +376,13 @@ def _lint_script_parts(script_parts, script_cache, lint_error, conf, import_callback): def report_lint(node, errname): - _report(node.start_pos(), errname, True) + # TODO: This is ugly hardcoding to improve the error positioning of + # "missing_semicolon" errors. + if errname == 'missing_semicolon' or errname == 'missing_semicolon_for_lambda': + pos = node.end_pos() + else: + pos = node.start_pos() + _report(pos, errname, True) def report_native(pos, errname): _report(pos, errname, False) Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/pyjsl/warnings.py 2009-03-03 17:02:59 UTC (rev 238) @@ -22,6 +22,24 @@ import visitation from pyspidermonkey import tok, op +_ALL_TOKENS = tuple(filter(lambda x: x != tok.EOF, tok.__dict__.values())) + +def _get_assigned_lambda(node): + """ Given a node "x = function() {}", returns "function() {}". + """ + value = None + if node.kind == tok.SEMI: + assign_node, = node.kids + if assign_node and assign_node.kind == tok.ASSIGN: + ignored, value = assign_node.kids + elif node.kind == tok.VAR: + variables = node.kids + if variables: + value, = variables[-1].kids + + if value and value.kind == tok.FUNCTION and value.opcode == op.ANONFUNOBJ: + return value + # TODO: document inspect, node:opcode, etc warnings = { @@ -63,6 +81,7 @@ 'var_hides_arg': 'variable {0} hides argument', 'duplicate_formal': 'TODO', 'missing_semicolon': 'missing semicolon', + 'missing_semicolon_for_lambda': 'missing semicolon for lambda assignment', 'ambiguous_newline': 'unexpected end of line; it is ambiguous whether these lines are part of the same statement', 'missing_option_explicit': 'the "option explicit" control comment is missing', 'partial_option_explicit': 'the "option explicit" control comment, if used, must be in the first script tag', @@ -538,10 +557,21 @@ def duplicate_formal(node): pass -@lookfor() +@lookfor(*_ALL_TOKENS) def missing_semicolon(node): - pass + if node.no_semi: + if not _get_assigned_lambda(node): + raise LintWarning, node +@lookfor(*_ALL_TOKENS) +def missing_semicolon_for_lambda(node): + if node.no_semi: + # spidermonkey sometimes returns incorrect positions for var + # statements, so use the position of the lambda instead. + lambda_ = _get_assigned_lambda(node) + if lambda_: + raise LintWarning, lambda_ + @lookfor() def ambiguous_newline(node): pass Modified: trunk/pyspidermonkey/pyspidermonkey.c =================================================================== --- trunk/pyspidermonkey/pyspidermonkey.c 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/pyspidermonkey/pyspidermonkey.c 2009-03-03 17:02:59 UTC (rev 238) @@ -303,6 +303,9 @@ goto fail; } + if (PyObject_SetAttrString(pynode, "no_semi", PyBool_FromLong(jsnode->pn_no_semi)) == -1) + goto fail; + switch (jsnode->pn_arity) { case PN_FUNC: kids = PyTuple_New(1); Modified: trunk/spidermonkey/src/jsparse.c =================================================================== --- trunk/spidermonkey/src/jsparse.c 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/spidermonkey/src/jsparse.c 2009-03-03 17:02:59 UTC (rev 238) @@ -248,6 +248,7 @@ pn->pn_next = NULL; pn->pn_ts = ts; pn->pn_source = NULL; + pn->pn_no_semi = JS_FALSE; return pn; } @@ -324,6 +325,7 @@ pn->pn_next = NULL; pn->pn_ts = NULL; pn->pn_source = NULL; + pn->pn_no_semi = JS_FALSE; return pn; } @@ -2738,7 +2740,8 @@ * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ - (void) js_MatchToken(cx, ts, TOK_SEMI); + if (!js_MatchToken(cx, ts, TOK_SEMI)) + pn->pn_no_semi = JS_TRUE; return pn; } break; @@ -3476,6 +3479,8 @@ return NULL; pn->pn_type = TOK_SEMI; pn->pn_kid = NULL; + if (tt == TOK_EOL) + pn->pn_no_semi = JS_TRUE; return pn; #if JS_HAS_DEBUGGER_KEYWORD @@ -3588,7 +3593,8 @@ } } - (void) js_MatchToken(cx, ts, TOK_SEMI); + if (!js_MatchToken(cx, ts, TOK_SEMI)) + pn->pn_no_semi = JS_TRUE; return pn; } @@ -4311,6 +4317,7 @@ pn2->pn_next = NULL; pn2->pn_ts = ts; pn2->pn_source = NULL; + pn2->pn_no_semi = JS_FALSE; pn = pn2; } } Modified: trunk/spidermonkey/src/jsparse.h =================================================================== --- trunk/spidermonkey/src/jsparse.h 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/spidermonkey/src/jsparse.h 2009-03-03 17:02:59 UTC (rev 238) @@ -317,6 +317,7 @@ JSParseNode *pn_next; /* to align dval and pn_u on RISCs */ JSTokenStream *pn_ts; /* token stream for error reports */ JSAtom *pn_source; /* saved source for decompilation */ + JSBool pn_no_semi; /* missing semicolon */ }; #define pn_funAtom pn_u.func.funAtom Modified: trunk/test.py =================================================================== --- trunk/test.py 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/test.py 2009-03-03 17:02:59 UTC (rev 238) @@ -32,7 +32,6 @@ for warning in regexp.findall(lines[i]): # TODO: implement these unimpl_warnings = ('ambiguous_newline', 'dup_option_explicit', - 'missing_semicolon' ) if not warning in unimpl_warnings: warnings.append((i, warning)) Deleted: trunk/tests/conf/lambda_assign_requires_semicolon.js =================================================================== --- trunk/tests/conf/lambda_assign_requires_semicolon.js 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/tests/conf/lambda_assign_requires_semicolon.js 2009-03-03 17:02:59 UTC (rev 238) @@ -1,43 +0,0 @@ -/*conf:-lambda_assign_requires_semicolon*/ - - -/* Test with a simple variable. */ -var x = function() { - return {}; -} -x(); - -var a, b = function() { }, c -b(); /*warning:missing_semicolon*/ -var d, e = function() { } -e(); - -var y; -y = function() { - return []; -} -y(); - -global = function() { - return null; -} -global(); - -function Foo() -{ - this.bar = 10; - - /* Test an assignment to a member. */ - this.setBar = function(bar) { - this.bar = bar; - } - - this.setBar(this.bar * 2); -} - -/* Test an assignment to a prototype. */ -Foo.prototype.getBar = function() { - return this.bar; -} - -var foo = new Foo(); Modified: trunk/tests/control_comments/declare.js =================================================================== --- trunk/tests/control_comments/declare.js 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/tests/control_comments/declare.js 2009-03-03 17:02:59 UTC (rev 238) @@ -9,8 +9,8 @@ /*jsl:declare document*//*warning:redeclared_var*/ } -var i = 10 -/*jsl:declare sample*//*warning:missing_semicolon*/ +var i = 10 /*warning:missing_semicolon*/ +/*jsl:declare sample*/ /* declare was scoped */ window.alert('JavaScript Lint');/*warning:undeclared_identifier*/ Modified: trunk/tests/warnings/missing_semicolon.js =================================================================== --- trunk/tests/warnings/missing_semicolon.js 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/tests/warnings/missing_semicolon.js 2009-03-03 17:02:59 UTC (rev 238) @@ -1,19 +1,23 @@ /*jsl:option explicit*/ + function missing_semicolon() { /* missing semicolon after return */ function MissingSemicolonOnReturnStatement() { - return 0 - } /*warning:missing_semicolon*/ + return 0 /*warning:missing_semicolon*/ + } + function MissingSemicolonOnReturnStatement2() { return 0 } /*warning:missing_semicolon*/ - /* missing semicolon after return */ /* missing semicolon after lambda */ function x() { - this.y = function() { return 0 } /*warning:missing_semicolon*/ - } /*warning:missing_semicolon*/ + this.y = function() { return 0; } /*warning:missing_semicolon_for_lambda*/ + } - /* missing semicolon after return */ /* missing semicolon after lambda */ x.prototype.z = function() { - return 1 - } /*warning:missing_semicolon*/ -} /*warning:missing_semicolon*/ + return 1; + } /*warning:missing_semicolon_for_lambda*/ + + do x++; + while (x < 10) /*warning:missing_semicolon*/ +} + Copied: trunk/tests/warnings/missing_semicolon_for_lambda.js (from rev 237, trunk/tests/conf/lambda_assign_requires_semicolon.js) =================================================================== --- trunk/tests/warnings/missing_semicolon_for_lambda.js (rev 0) +++ trunk/tests/warnings/missing_semicolon_for_lambda.js 2009-03-03 17:02:59 UTC (rev 238) @@ -0,0 +1,43 @@ +/*jsl:option explicit*/ +/*jsl:declare global*/ + +/* Test with a simple variable. */ +var x = function() { + return {}; +} /*warning:missing_semicolon_for_lambda*/ +x(); + +var a, b = function() { }, c /*warning:missing_semicolon*/ +b(); +var d, e = function() { } /*warning:missing_semicolon_for_lambda*/ +e(); + +var y; +y = function() { + return []; +} /*warning:missing_semicolon_for_lambda*/ +y(); + +global = function() { + return null; +} /*warning:missing_semicolon_for_lambda*/ +global(); + +function Foo() +{ + this.bar = 10; + + /* Test an assignment to a member. */ + this.setBar = function(bar) { + this.bar = bar; + } /*warning:missing_semicolon_for_lambda*/ + + this.setBar(this.bar * 2); +} + +/* Test an assignment to a prototype. */ +Foo.prototype.getBar = function() { + return this.bar; +} /*warning:missing_semicolon_for_lambda*/ + +var foo = new Foo(); Modified: trunk/tests/warnings/unreferenced_identifier.js =================================================================== --- trunk/tests/warnings/unreferenced_identifier.js 2008-09-01 15:57:37 UTC (rev 237) +++ trunk/tests/warnings/unreferenced_identifier.js 2009-03-03 17:02:59 UTC (rev 238) @@ -15,7 +15,7 @@ /* Test an unreferenced parameter. */ var z = new function(unreferenced_parm) { /*warning:unreferenced_identifier*/ - } + }; z.prop = 42; /* Test an unreferenced variable. */ @@ -80,7 +80,7 @@ function get_callback(parm) { return function() { return parm; - } + }; } return get_callback(42); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |