[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.
|