[javascriptlint-commit] SF.net SVN: javascriptlint:[217] trunk
Status: Beta
Brought to you by:
matthiasmiller
From: <mat...@us...> - 2008-08-26 03:11:07
|
Revision: 217 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=217&view=rev Author: matthiasmiller Date: 2008-08-26 03:11:02 +0000 (Tue, 26 Aug 2008) Log Message: ----------- unreferenced_identifier: first cut at implementation Modified Paths: -------------- trunk/pyjsl/lint.py trunk/pyjsl/warnings.py trunk/tests/control_comments/declare.js trunk/tests/control_comments/option_explicit-with.js trunk/tests/control_comments/option_explicit.js trunk/tests/warnings/ambiguous_newline.js trunk/tests/warnings/anon_no_return_value.js trunk/tests/warnings/duplicate_formal.js trunk/tests/warnings/inc_dec_within_stmt.js trunk/tests/warnings/misplaced_regex.js trunk/tests/warnings/missing_break.js trunk/tests/warnings/missing_semicolon.js trunk/tests/warnings/no_return_value.js trunk/tests/warnings/redeclared_var.js trunk/tests/warnings/spidermonkey/bad_backref.js trunk/tests/warnings/spidermonkey/invalid_backref.js trunk/tests/warnings/var_hides_arg.js Added Paths: ----------- trunk/tests/warnings/unreferenced_identifier.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/pyjsl/lint.py 2008-08-26 03:11:02 UTC (rev 217) @@ -74,7 +74,6 @@ class Scope: def __init__(self, node): """ node may be None """ - self._is_with_scope = node and node.kind == tok.WITH self._parent = None self._kids = [] self._identifiers = {} @@ -83,15 +82,11 @@ def add_scope(self, node): self._kids.append(Scope(node)) self._kids[-1]._parent = self - if self._is_with_scope: - self._kids[-1]._is_with_scope = True return self._kids[-1] def add_declaration(self, name, node): - if not self._is_with_scope: - self._identifiers[name] = node + self._identifiers[name] = node def add_reference(self, name, node): - if not self._is_with_scope: - self._references.append((name, node)) + self._references.append((name, node)) def get_identifier(self, name): if name in self._identifiers: return self._identifiers[name] @@ -106,14 +101,55 @@ if self._parent: return self._parent.resolve_identifier(name) return None - def get_undeclared_identifiers(self): - identifiers = [] + def get_unreferenced_and_undeclared_identifiers(self): + """ Returns a tuple of unreferenced and undeclared, where each is a list + of (scope, name, node) tuples. + """ + unreferenced = {} + undeclared = [] + self._find_unreferenced_and_undeclared(unreferenced, undeclared, False) + + # Convert "unreferenced" from a dictionary of: + # { (scope, name): node } + # to a list of: + # [ (scope, name, node) ] + # sorted by node position. + unreferenced = [(key[0], key[1], node) for key, node + in unreferenced.items()] + unreferenced.sort(key=lambda x: x[2].start_pos()) + + return unreferenced, undeclared + def _find_unreferenced_and_undeclared(self, unreferenced, undeclared, + is_in_with_scope): + """ unreferenced is a dictionary, such that: + (scope, name): node + } + undeclared is a list, such that: [ + (scope, name, node) + ] + """ + is_in_with_scope = is_in_with_scope or self._node.kind == tok.WITH + + # Add all identifiers as unreferenced. Children scopes will remove + # them if they are referenced. Variables need to be keyed by name + # instead of node, because function parameters share the same node. + for name, node in self._identifiers.items(): + unreferenced[(self, name)] = node + + # Remove all declared variables from the "unreferenced" set; add all + # undeclared variables to the "undeclared" list. + for name, node in self._references: + resolved = self.resolve_identifier(name) + if resolved: + unreferenced.pop((resolved[0], name), None) + else: + # with statements cannot have undeclared identifiers. + if not is_in_with_scope: + undeclared.append((self, name, node)) + for child in self._kids: - identifiers += child.get_undeclared_identifiers() - for name, node in self._references: - if not self.resolve_identifier(name): - identifiers.append(node) - return identifiers + child._find_unreferenced_and_undeclared(unreferenced, undeclared, + is_in_with_scope) def find_scope(self, node): if not self._node: return None @@ -298,9 +334,14 @@ else: declare_scope.add_declaration(name, node) - for node in scope.get_undeclared_identifiers(): - if not node.atom in imports: + unreferenced, undeclared = scope.get_unreferenced_and_undeclared_identifiers() + for decl_scope, name, node in undeclared: + if not name in imports: report(node, 'undeclared_identifier') + for ref_scope, name, node in unreferenced: + # Ignore the outer scope. + if ref_scope != scope: + report(node, 'unreferenced_identifier') def _getreporter(visitor, report): def onpush(node): @@ -328,11 +369,13 @@ @visitation.visit('push', tok.NAME) def _name(self, node): if node.node_index == 0 and node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC: - pass # left side of object literal - elif node.parent.kind == tok.CATCH: + return # left side of object literal + if node.parent.kind == tok.VAR: + _warn_or_declare(scopes[-1], node.atom, node, report) + return + if node.parent.kind == tok.CATCH: scopes[-1].add_declaration(node.atom, node) - else: - scopes[-1].add_reference(node.atom, node) + scopes[-1].add_reference(node.atom, node) @visitation.visit('push', tok.FUNCTION) def _push_func(self, node): @@ -350,11 +393,6 @@ def _pop_scope(self, node): scopes.pop() - @visitation.visit('push', tok.VAR) - def _push_var(self, node): - for kid in node.kids: - _warn_or_declare(scopes[-1], kid.atom, node, report) - return scope_checks Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/pyjsl/warnings.py 2008-08-26 03:11:02 UTC (rev 217) @@ -56,6 +56,7 @@ 'mismatch_ctrl_comments': 'mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence', 'redeclared_var': 'redeclaration of {0} {1}', 'undeclared_identifier': 'undeclared identifier: {0}', + 'unreferenced_identifier': 'identifier is declared but never referenced: {0}', 'jsl_cc_not_understood': 'couldn\'t understand control comment using /*jsl:keyword*/ syntax', 'nested_comment': 'nested comment', 'legacy_cc_not_understood': 'couldn\'t understand control comment using /*@keyword@*/ syntax', Modified: trunk/tests/control_comments/declare.js =================================================================== --- trunk/tests/control_comments/declare.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/control_comments/declare.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function declare() { window.alert('http://www.javascriptlint.com/'); /*jsl:declare window*/ /*warning:redeclared_var*/ Modified: trunk/tests/control_comments/option_explicit-with.js =================================================================== --- trunk/tests/control_comments/option_explicit-with.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/control_comments/option_explicit-with.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function option_explicit() { var o = {}; Modified: trunk/tests/control_comments/option_explicit.js =================================================================== --- trunk/tests/control_comments/option_explicit.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/control_comments/option_explicit.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ var g; function option_explicit(parm) { /* legal - j is declared */ Modified: trunk/tests/warnings/ambiguous_newline.js =================================================================== --- trunk/tests/warnings/ambiguous_newline.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/ambiguous_newline.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function ambiguous_newline() { /* the EOL test is based on JSLint's documentation */ var a, b, i, o, s; Modified: trunk/tests/warnings/anon_no_return_value.js =================================================================== --- trunk/tests/warnings/anon_no_return_value.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/anon_no_return_value.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function anon_no_return_value() { var error1 = function(b) { if (b) Modified: trunk/tests/warnings/duplicate_formal.js =================================================================== --- trunk/tests/warnings/duplicate_formal.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/duplicate_formal.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,5 +1,5 @@ /*jsl:option explicit*/ function duplicate_formal(duplicate, duplicate) { /*warning:duplicate_formal*/ - return; + return duplicate; } Modified: trunk/tests/warnings/inc_dec_within_stmt.js =================================================================== --- trunk/tests/warnings/inc_dec_within_stmt.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/inc_dec_within_stmt.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function inc_dec_within_stmt() { var i, s; Modified: trunk/tests/warnings/misplaced_regex.js =================================================================== --- trunk/tests/warnings/misplaced_regex.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/misplaced_regex.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function misplaced_regex() { var i, re; Modified: trunk/tests/warnings/missing_break.js =================================================================== --- trunk/tests/warnings/missing_break.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/missing_break.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function missing_break() { var i, o, s; Modified: trunk/tests/warnings/missing_semicolon.js =================================================================== --- trunk/tests/warnings/missing_semicolon.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/missing_semicolon.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,7 +1,7 @@ /*jsl:option explicit*/ function missing_semicolon() { /* missing semicolon after return */ - function MissingSemicolonOnReturnStatement() { + function MissingSemicolonOnReturnStatement() { /*warning:unreferenced_identifier*/ return 0 } /*warning:missing_semicolon*/ Modified: trunk/tests/warnings/no_return_value.js =================================================================== --- trunk/tests/warnings/no_return_value.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/no_return_value.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function no_return_value() { function error1(b) { if (b) Modified: trunk/tests/warnings/redeclared_var.js =================================================================== --- trunk/tests/warnings/redeclared_var.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/redeclared_var.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function redeclared_var() { var duplicate; var duplicate; /*warning:redeclared_var*/ Modified: trunk/tests/warnings/spidermonkey/bad_backref.js =================================================================== --- trunk/tests/warnings/spidermonkey/bad_backref.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/spidermonkey/bad_backref.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,5 +1,5 @@ /*jsl:option explicit*/ function bad_backref() { /* illegal - one 1 backreference */ - var re = /(.)\2/; /*warning:bad_backref*/ + return /(.)\2/; /*warning:bad_backref*/ } Modified: trunk/tests/warnings/spidermonkey/invalid_backref.js =================================================================== --- trunk/tests/warnings/spidermonkey/invalid_backref.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/spidermonkey/invalid_backref.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,5 +1,5 @@ /*jsl:option explicit*/ function invalid_backref() { /* illegal - \0 is not a valid regex backreference */ - var re = /\0/; /*warning:invalid_backref*/ + return /\0/; /*warning:invalid_backref*/ } Added: trunk/tests/warnings/unreferenced_identifier.js =================================================================== --- trunk/tests/warnings/unreferenced_identifier.js (rev 0) +++ trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 03:11:02 UTC (rev 217) @@ -0,0 +1,56 @@ +/* outer-level functions shouldn't warn */ +var unreferenced_global; +function unreferenced_identifier() { + /* Test an unreferenced function. */ + function unreferenced_func() { /*warning:unreferenced_identifier*/ + return true; + } + function referenced_func() { + } + var referenced_var = referenced_func; + referenced_var(); + + /* Test an unreferenced parameter. */ + var z = new function(unreferenced_parm) { /*warning:unreferenced_identifier*/ + } + z.prop = 42; + + /* Test an unreferenced variable. */ + var unreferenced_variable = 100; /*warning:unreferenced_identifier*/ + + /* An unreferenced duplicate parameter should give one warning. */ + function func_with_dup(unref_dup_parm, unref_dup_parm) { /*warning:unreferenced_identifier*/ /*warning:duplicate_formal*/ + } + func_with_dup(); + + /* An unreferenced duplicate variable should give one warning. */ + var unref_dup_var; /*warning:unreferenced_identifier*/ + var unref_dup_var; /*warning:redeclared_var*/ + + /* Test a try/catch. The error doesn't need to be referenced. */ + var can; + try { + can = true; /* we think we can... */ + } + catch(err) { + can = false; /* ...but maybe not! */ + } + + /* Test a with statement. */ + var withobj = {}; + var withval = 42; + with (withobj) /*warning:with_statement*/ + { + prop_a = withval; + var innerval = '42'; + prop_b = innerval; + } + + /* Test nested scopes. */ + function get_callback(parm) { + return function() { + return parm; + } + } + return get_callback(42); +} Modified: trunk/tests/warnings/var_hides_arg.js =================================================================== --- trunk/tests/warnings/var_hides_arg.js 2008-08-24 00:39:17 UTC (rev 216) +++ trunk/tests/warnings/var_hides_arg.js 2008-08-26 03:11:02 UTC (rev 217) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function var_hides_arg(duplicate1, duplicate2) { var duplicate1; /*warning:var_hides_arg*/ function inner() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |