javascriptlint-commit Mailing List for JavaScript Lint (Page 7)
Status: Beta
Brought to you by:
matthiasmiller
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
(42) |
Apr
(15) |
May
(2) |
Jun
|
Jul
|
Aug
(33) |
Sep
(3) |
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
|
Feb
|
Mar
(5) |
Apr
|
May
(2) |
Jun
|
Jul
|
Aug
(2) |
Sep
|
Oct
(43) |
Nov
(4) |
Dec
(1) |
2010 |
Jan
|
Feb
|
Mar
|
Apr
(6) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2013 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(20) |
Oct
(23) |
Nov
|
Dec
(1) |
2014 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(4) |
Nov
|
Dec
|
2016 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(18) |
2018 |
Jan
(7) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(8) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <mat...@us...> - 2008-09-01 15:57:39
|
Revision: 237 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=237&view=rev Author: matthiasmiller Date: 2008-09-01 15:57:37 +0000 (Mon, 01 Sep 2008) Log Message: ----------- fix for Python 2.4 Modified Paths: -------------- trunk/pyjsl/warnings.py Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-09-01 14:04:10 UTC (rev 236) +++ trunk/pyjsl/warnings.py 2008-09-01 15:57:37 UTC (rev 237) @@ -138,8 +138,10 @@ exit_points.remove(None) # Convert "break" into None - exit_points = set(map(lambda node: node \ - if node and node.kind != tok.BREAK else None, exit_points)) + def break_to_none(node): + if node and node.kind != tok.BREAK: + return node + exit_points = set(map(break_to_none, exit_points)) # Check if the switch had a default case if not switch_has_default: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-09-01 14:04:12
|
Revision: 236 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=236&view=rev Author: matthiasmiller Date: 2008-09-01 14:04:10 +0000 (Mon, 01 Sep 2008) Log Message: ----------- allow jsparse to locate possible comments before the script is parsed Modified Paths: -------------- trunk/pyjsl/jsparse.py trunk/pyjsl/lint.py Modified: trunk/pyjsl/jsparse.py =================================================================== --- trunk/pyjsl/jsparse.py 2008-09-01 13:56:13 UTC (rev 235) +++ trunk/pyjsl/jsparse.py 2008-09-01 14:04:10 UTC (rev 236) @@ -145,7 +145,7 @@ return True -def _parse_comments(script, node_positions, ignore_ranges): +def findpossiblecomments(script, node_positions): pos = 0 single_line_re = r"//[^\r\n]*" multi_line_re = r"/\*(.*?)\*/" @@ -169,31 +169,30 @@ opcode = opcode[5:].lower() start_offset = match.start() - end_offset = match.end() + end_offset = match.end()-1 - # Make sure it doesn't start in a string or regexp - if not ignore_ranges.has(start_offset): - start_pos = node_positions.from_offset(start_offset) - end_pos = node_positions.from_offset(end_offset) - kwargs = { - 'type': 'COMMENT', - 'atom': comment_text, - 'opcode': opcode, - '_start_line': start_pos.line, - '_start_col': start_pos.col, - '_end_line': end_pos.line, - '_end_col': end_pos.col, - 'parent': None, - 'kids': [], - 'node_index': None - } - comment_node = _Node() - comment_node.__dict__.update(kwargs) - comments.append(comment_node) - pos = match.end() - else: - pos = match.start()+1 + start_pos = node_positions.from_offset(start_offset) + end_pos = node_positions.from_offset(end_offset) + kwargs = { + 'type': 'COMMENT', + 'atom': comment_text, + 'opcode': opcode, + '_start_line': start_pos.line, + '_start_col': start_pos.col, + '_end_line': end_pos.line, + '_end_col': end_pos.col, + 'parent': None, + 'kids': [], + 'node_index': None + } + comment_node = _Node() + comment_node.__dict__.update(kwargs) + comments.append(comment_node) + # Start searching immediately after the start of the comment in case + # this one was within a string or a regexp. + pos = match.start()+1 + def parse(script, error_callback, startpos=None): """ All node positions will be relative to startpos. This allows scripts to be embedded in a file (for example, HTML). @@ -207,28 +206,37 @@ return pyspidermonkey.parse(script, _Node, _wrapped_callback, startpos.line, startpos.col) -def parsecomments(script, root_node, startpos=None): - """ All node positions will be relative to startpos. This allows scripts - to be embedded in a file (for example, HTML). - """ - positions = NodePositions(script, startpos) +def filtercomments(possible_comments, node_positions, root_node): comment_ignore_ranges = NodeRanges() def process(node): if node.kind == tok.NUMBER: - node.atom = positions.text(node.start_pos(), node.end_pos()) + node.atom = node_positions.text(node.start_pos(), node.end_pos()) elif node.kind == tok.STRING or \ (node.kind == tok.OBJECT and node.opcode == op.REGEXP): - start_offset = positions.to_offset(node.start_pos()) - end_offset = positions.to_offset(node.end_pos()) - 1 + start_offset = node_positions.to_offset(node.start_pos()) + end_offset = node_positions.to_offset(node.end_pos()) - 1 comment_ignore_ranges.add(start_offset, end_offset) for kid in node.kids: if kid: process(kid) process(root_node) - return _parse_comments(script, positions, comment_ignore_ranges) + comments = [] + for comment in possible_comments: + start_offset = node_positions.to_offset(comment.start_pos()) + end_offset = node_positions.to_offset(comment.end_pos()) + if comment_ignore_ranges.has(start_offset): + continue + comment_ignore_ranges.add(start_offset, end_offset) + comments.append(comment) + return comments +def findcomments(script, root_node, start_pos=None): + node_positions = NodePositions(script, start_pos) + possible_comments = findpossiblecomments(script, node_positions) + return filtercomments(possible_comments, node_positions, root_node) + def is_compilable_unit(script): return pyspidermonkey.is_compilable_unit(script) @@ -258,7 +266,7 @@ class TestComments(unittest.TestCase): def _test(self, script, expected_comments): root = parse(script, lambda line, col, msg: None) - comments = parsecomments(script, root) + comments = findcomments(script, root) encountered_comments = [node.atom for node in comments] self.assertEquals(encountered_comments, list(expected_comments)) def testSimpleComments(self): @@ -386,7 +394,7 @@ def testComments(self): def testcomment(comment, startpos, expectedpos): root = parse(comment, None, startpos) - comment, = parsecomments(comment, root, startpos) + comment, = findcomments(comment, root, startpos) self.assertEquals(comment.start_pos(), expectedpos) for comment in ('/*comment*/', '//comment'): testcomment(comment, None, NodePos(0,0)) Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-09-01 13:56:13 UTC (rev 235) +++ trunk/pyjsl/lint.py 2008-09-01 14:04:10 UTC (rev 236) @@ -288,6 +288,9 @@ fallthrus = [] passes = [] + node_positions = jsparse.NodePositions(script, scriptpos) + possible_comments = jsparse.findpossiblecomments(script, node_positions) + root = jsparse.parse(script, parse_error, scriptpos) if not root: # Report errors and quit. @@ -295,7 +298,7 @@ report_native(pos, msg) return - comments = jsparse.parsecomments(script, root, scriptpos) + comments = jsparse.filtercomments(possible_comments, node_positions, root) start_ignore = None for comment in comments: cc = _parse_control_comment(comment) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-09-01 13:56:16
|
Revision: 235 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=235&view=rev Author: matthiasmiller Date: 2008-09-01 13:56:13 +0000 (Mon, 01 Sep 2008) Log Message: ----------- move knowledge of script excerpts into NodePositions Modified Paths: -------------- trunk/pyjsl/jsparse.py Modified: trunk/pyjsl/jsparse.py =================================================================== --- trunk/pyjsl/jsparse.py 2008-08-28 16:24:36 UTC (rev 234) +++ trunk/pyjsl/jsparse.py 2008-09-01 13:56:13 UTC (rev 235) @@ -21,9 +21,10 @@ class NodePositions: " Given a string, allows [x] lookups for NodePos line and column numbers." - def __init__(self, text): + def __init__(self, text, start_pos=None): # Find the length of each line and incrementally sum all of the lengths # to determine the ending position of each line. + self._start_pos = start_pos self._lines = text.splitlines(True) lines = [0] + [len(x) for x in self._lines] for x in range(1, len(lines)): @@ -32,18 +33,34 @@ def from_offset(self, offset): line = bisect.bisect(self._line_offsets, offset)-1 col = offset - self._line_offsets[line] + if self._start_pos: + if line == 0: + col += self._start_pos.col + line += self._start_pos.line return NodePos(line, col) def to_offset(self, pos): + pos = self._to_rel_pos(pos) offset = self._line_offsets[pos.line] + pos.col assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num return offset def text(self, start, end): assert start <= end + start, end = self._to_rel_pos(start), self._to_rel_pos(end) # Trim the ending first in case it's a single line. lines = self._lines[start.line:end.line+1] lines[-1] = lines[-1][:end.col+1] lines[0] = lines[0][start.col:] return ''.join(lines) + def _to_rel_pos(self, pos): + " converts a position to a position relative to self._start_pos " + if not self._start_pos: + return pos + line, col = pos.line, pos.col + line -= self._start_pos.line + if line == 0: + col -= self._start_pos.col + assert line >= 0 and col >= 0 # out-of-bounds node position + return NodePos(line, col) class NodeRanges: def __init__(self): @@ -194,11 +211,7 @@ """ All node positions will be relative to startpos. This allows scripts to be embedded in a file (for example, HTML). """ - # Use dummy text to rebase node positions. - if startpos: - script = ('\n' * startpos.line) + (' ' * startpos.col) + script - - positions = NodePositions(script) + positions = NodePositions(script, startpos) comment_ignore_ranges = NodeRanges() def process(node): @@ -290,6 +303,14 @@ self.assertEquals(pos.to_offset(NodePos(0, 2)), 2) self.assertEquals(pos.to_offset(NodePos(1, 0)), 5) self.assertEquals(pos.to_offset(NodePos(3, 1)), 11) + def testStartPos(self): + pos = NodePositions('abc\r\ndef\n\nghi', NodePos(3,4)) + self.assertEquals(pos.to_offset(NodePos(3, 4)), 0) + self.assertEquals(pos.to_offset(NodePos(3, 5)), 1) + self.assertEquals(pos.from_offset(0), NodePos(3, 4)) + self.assertEquals(pos.text(NodePos(3, 4), NodePos(3, 4)), 'a') + self.assertEquals(pos.text(NodePos(3, 4), NodePos(3, 6)), 'abc') + self.assertEquals(pos.text(NodePos(3, 6), NodePos(4, 2)), 'c\r\ndef') class TestNodeRanges(unittest.TestCase): def testAdd(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 16:24:40
|
Revision: 234 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=234&view=rev Author: matthiasmiller Date: 2008-08-28 16:24:36 +0000 (Thu, 28 Aug 2008) Log Message: ----------- handle IE conditional comments Modified Paths: -------------- trunk/pyjsl/htmlparse.py Modified: trunk/pyjsl/htmlparse.py =================================================================== --- trunk/pyjsl/htmlparse.py 2008-08-28 14:27:08 UTC (rev 233) +++ trunk/pyjsl/htmlparse.py 2008-08-28 16:24:36 UTC (rev 234) @@ -41,6 +41,10 @@ self._node_positions = jsparse.NodePositions(self.rawdata + data) HTMLParser.HTMLParser.feed(self, data) + def unknown_decl(self, data): + # Ignore unknown declarations instead of raising an exception. + pass + def getscripts(self): return self._scripts @@ -77,4 +81,9 @@ "", "<!--\nvar s = '<script></script>';\n-->" ]) - + def testConditionalComments(self): + html = """ +<!--[if IE]>This is Internet Explorer.<![endif]--> +<![if !IE]>This is not Internet Explorer<![endif]> +""" + findscripts(html) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 14:27:11
|
Revision: 233 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=233&view=rev Author: matthiasmiller Date: 2008-08-28 14:27:08 +0000 (Thu, 28 Aug 2008) Log Message: ----------- no_return_value: fix for if statements with else Modified Paths: -------------- trunk/pyjsl/warnings.py trunk/tests/warnings/no_return_value.js Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-28 04:58:29 UTC (rev 232) +++ trunk/pyjsl/warnings.py 2008-08-28 14:27:08 UTC (rev 233) @@ -118,6 +118,8 @@ exit_points = _get_exit_points(if_) if else_: exit_points |= _get_exit_points(else_) + else: + exit_points.add(None) elif node.kind == tok.SWITCH: exit_points = set([None]) Modified: trunk/tests/warnings/no_return_value.js =================================================================== --- trunk/tests/warnings/no_return_value.js 2008-08-28 04:58:29 UTC (rev 232) +++ trunk/tests/warnings/no_return_value.js 2008-08-28 14:27:08 UTC (rev 233) @@ -16,6 +16,12 @@ } } + function error3(b) { /*warning:no_return_value*/ + if (b) { + return ""; + } + } + function correct(b) { if (b) return; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 04:58:31
|
Revision: 232 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=232&view=rev Author: matthiasmiller Date: 2008-08-28 04:58:29 +0000 (Thu, 28 Aug 2008) Log Message: ----------- a rough cut at supporting HTML files Modified Paths: -------------- trunk/jsl.py trunk/pyjsl/lint.py Added Paths: ----------- trunk/tests/html/include.ecmascript trunk/tests/html/include.html Modified: trunk/jsl.py =================================================================== --- trunk/jsl.py 2008-08-28 04:34:11 UTC (rev 231) +++ trunk/jsl.py 2008-08-28 04:58:29 UTC (rev 232) @@ -42,9 +42,8 @@ def run_tests(): for file in get_test_files(): - if file.endswith('.htm') or file.endswith('.html'): - continue #TODO - elif file.endswith('.js'): + ext = os.path.splitext(file)[1] + if ext in ('.htm', '.html', '.js'): try: test.run(file) except test.TestError, error: Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-28 04:34:11 UTC (rev 231) +++ trunk/pyjsl/lint.py 2008-08-28 04:58:29 UTC (rev 232) @@ -4,6 +4,7 @@ import re import conf +import htmlparse import jsparse import visitation import warnings @@ -177,27 +178,72 @@ node.end_pos() <= self._node.end_pos()): return self +class _Script: + def __init__(self): + self._imports = set() + self.scope = Scope() + def importscript(self, script): + self._imports.add(script) + def hasglobal(self, name): + return not self._findglobal(name, set()) is None + def _findglobal(self, name, searched): + """ searched is a set of all searched scripts """ + # Avoid recursion. + if self in searched: + return + + # Check this scope. + if self.scope.get_identifier(name): + return self + searched.add(self) + + # Search imported scopes. + for script in self._imports: + global_ = script._findglobal(name, searched) + if global_: + return global_ + def lint_files(paths, lint_error, conf=conf.Conf()): - def lint_file(path): + def lint_file(path, kind): def import_script(import_path): import_path = os.path.join(os.path.dirname(path), import_path) - return lint_file(import_path) + return lint_file(import_path, 'js') def _lint_error(*args): return lint_error(normpath, *args) normpath = util.normpath(path) - if not normpath in lint_cache: - lint_cache[normpath] = {} - script = util.readfile(path) - print normpath - _lint_script(script, lint_cache[normpath], _lint_error, conf, import_script) + if normpath in lint_cache: + return lint_cache[normpath] + print normpath + contents = util.readfile(path) + lint_cache[normpath] = _Script() + + script_parts = [] + if kind == 'js': + script_parts.append((None, contents)) + elif kind == 'html': + for script in htmlparse.findscripts(contents): + if script['src']: + other = import_script(script['src']) + lint_cache[normpath].importscript(other) + if script['script'].strip(): + script_parts.append((script['startpos'], script['script'])) + else: + assert False, 'Unsupported file kind: %s' % kind + + _lint_script_parts(script_parts, lint_cache[normpath], _lint_error, conf, import_script) return lint_cache[normpath] lint_cache = {} for path in paths: - lint_file(path) + ext = os.path.splitext(path)[1] + if ext.lower() in ['.htm', '.html']: + lint_file(path, 'html') + else: + lint_file(path, 'js') -def _lint_script(script, script_cache, lint_error, conf, import_callback): +def _lint_script_part(scriptpos, script, script_cache, conf, ignores, + report_native, report_lint, import_callback): def parse_error(row, col, msg): if not msg in ('anon_no_return_value', 'no_return_value', 'redeclared_var', 'var_hides_arg'): @@ -234,42 +280,22 @@ fallthrus.remove(fallthru) return - _report(node.start_pos(), errname, True) + report_lint(node, errname) - def _report(pos, errname, require_key): - try: - if not conf[errname]: - return - except KeyError, err: - if require_key: - raise - - for start, end in ignores: - if pos >= start and pos <= end: - return - - return lint_error(pos.line, pos.col, errname) - parse_errors = [] - ignores = [] declares = [] import_paths = [] fallthrus = [] passes = [] - root = jsparse.parse(script, parse_error) + root = jsparse.parse(script, parse_error, scriptpos) if not root: - # Cache empty results for this script. - assert not script_cache - script_cache['imports'] = set() - script_cache['scope'] = Scope() - # Report errors and quit. for pos, msg in parse_errors: - _report(pos, msg, False) + report_native(pos, msg) return - comments = jsparse.parsecomments(script, root) + comments = jsparse.parsecomments(script, root, scriptpos) start_ignore = None for comment in comments: cc = _parse_control_comment(comment) @@ -313,7 +339,7 @@ # Wait to report parse errors until loading jsl:ignore directives. for pos, msg in parse_errors: - _report(pos, msg, False) + report_native(pos, msg) # Find all visitors and convert them into "onpush" callbacks that call "report" visitors = { @@ -323,12 +349,8 @@ for kind, callbacks in visitors[event].items(): visitors[event][kind] = [_getreporter(callback, report) for callback in callbacks] - assert not script_cache - imports = script_cache['imports'] = set() - scope = script_cache['scope'] = Scope() - # Push the scope/variable checks. - visitation.make_visitors(visitors, [_get_scope_checks(scope, report)]) + visitation.make_visitors(visitors, [_get_scope_checks(script_cache.scope, report)]) # kickoff! _lint_node(root, visitors) @@ -339,28 +361,55 @@ report(fallthru, 'invalid_pass') # Process imports by copying global declarations into the universal scope. - imports |= set(conf['declarations']) - imports |= _globals for path in import_paths: - cache = import_callback(path) - imports |= cache['imports'] - imports |= set(cache['scope'].get_identifiers()) + script_cache.importscript(import_callback(path)) for name, node in declares: - declare_scope = scope.find_scope(node) + declare_scope = script_cache.scope.find_scope(node) if declare_scope.get_identifier(name): report(node, 'redeclared_var') else: declare_scope.add_declaration(name, node) +def _lint_script_parts(script_parts, script_cache, lint_error, conf, import_callback): + def report_lint(node, errname): + _report(node.start_pos(), errname, True) + + def report_native(pos, errname): + _report(pos, errname, False) + + def _report(pos, errname, require_key): + try: + if not conf[errname]: + return + except KeyError, err: + if require_key: + raise + + for start, end in ignores: + if pos >= start and pos <= end: + return + + return lint_error(pos.line, pos.col, errname) + + for scriptpos, script in script_parts: + ignores = [] + _lint_script_part(scriptpos, script, script_cache, conf, ignores, + report_native, report_lint, import_callback) + + scope = script_cache.scope unreferenced, undeclared = scope.get_unreferenced_and_undeclared_identifiers() for decl_scope, name, node in undeclared: - if not name in imports: - report(node, 'undeclared_identifier') + if name in conf['declarations']: + continue + if name in _globals: + continue + if not script_cache.hasglobal(name): + report_lint(node, 'undeclared_identifier') for ref_scope, name, node in unreferenced: # Ignore the outer scope. if ref_scope != scope: - report(node, 'unreferenced_identifier') + report_lint(node, 'unreferenced_identifier') def _getreporter(visitor, report): def onpush(node): Added: trunk/tests/html/include.ecmascript =================================================================== --- trunk/tests/html/include.ecmascript (rev 0) +++ trunk/tests/html/include.ecmascript 2008-08-28 04:58:29 UTC (rev 232) @@ -0,0 +1,10 @@ +var global_var = 42; +function GlobalFromInclude() { + var value; + this.set = function(newvalue) { + value = newvalue; + }; + this.get = function() { + return value; + }; +} Added: trunk/tests/html/include.html =================================================================== --- trunk/tests/html/include.html (rev 0) +++ trunk/tests/html/include.html 2008-08-28 04:58:29 UTC (rev 232) @@ -0,0 +1,21 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> +<html> +<head> + <title>JavaScript Lint Test Page</title> + <script src="include.ecmascript"></script> + <script type="text/javascript"><!-- + var myglobal = GlobalFromInclude(); + myglobal.set(global_var); + bogus = myglobal.get(); /*warning:undeclared_identifier*/ + var page_global = 42; + //--> + </script> + <script type="text/javascript"><!-- + myglobal.set(page_global); + undef(); /*warning:undeclared_identifier*/ + //--> + </script> +</head> +<body> +</body> +</html> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 04:34:13
|
Revision: 231 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=231&view=rev Author: matthiasmiller Date: 2008-08-28 04:34:11 +0000 (Thu, 28 Aug 2008) Log Message: ----------- allow adjusting node positions when parsing scripts Modified Paths: -------------- trunk/pyjsl/jsparse.py trunk/pyspidermonkey/pyspidermonkey.c Modified: trunk/pyjsl/jsparse.py =================================================================== --- trunk/pyjsl/jsparse.py 2008-08-28 00:25:42 UTC (rev 230) +++ trunk/pyjsl/jsparse.py 2008-08-28 04:34:11 UTC (rev 231) @@ -151,7 +151,7 @@ opcode = 'JSOP_CPP_COMMENT' opcode = opcode[5:].lower() - start_offset = match.start()+1 + start_offset = match.start() end_offset = match.end() # Make sure it doesn't start in a string or regexp @@ -177,15 +177,27 @@ else: pos = match.start()+1 -def parse(script, error_callback): +def parse(script, error_callback, startpos=None): + """ All node positions will be relative to startpos. This allows scripts + to be embedded in a file (for example, HTML). + """ def _wrapped_callback(line, col, msg): assert msg.startswith('JSMSG_') msg = msg[6:].lower() error_callback(line, col, msg) - return pyspidermonkey.parse(script, _Node, _wrapped_callback) + startpos = startpos or NodePos(0,0) + return pyspidermonkey.parse(script, _Node, _wrapped_callback, + startpos.line, startpos.col) -def parsecomments(script, root_node): +def parsecomments(script, root_node, startpos=None): + """ All node positions will be relative to startpos. This allows scripts + to be embedded in a file (for example, HTML). + """ + # Use dummy text to rebase node positions. + if startpos: + script = ('\n' * startpos.line) + (' ' * startpos.col) + script + positions = NodePositions(script) comment_ignore_ranges = NodeRanges() @@ -195,7 +207,7 @@ elif node.kind == tok.STRING or \ (node.kind == tok.OBJECT and node.opcode == op.REGEXP): start_offset = positions.to_offset(node.start_pos()) - end_offset = positions.to_offset(node.end_pos()) + end_offset = positions.to_offset(node.end_pos()) - 1 comment_ignore_ranges.add(start_offset, end_offset) for kid in node.kids: if kid: @@ -324,6 +336,45 @@ for text, result in tests: self.assertEquals(is_compilable_unit(text), result) +class TestLineOffset(unittest.TestCase): + def testErrorPos(self): + def geterror(script, startpos): + errors = [] + def onerror(line, col, msg): + errors.append((line, col, msg)) + parse(script, onerror, startpos) + self.assertEquals(len(errors), 1) + return errors[0] + self.assertEquals(geterror(' ?', None), (0, 1, 'syntax_error')) + self.assertEquals(geterror('\n ?', None), (1, 1, 'syntax_error')) + self.assertEquals(geterror(' ?', NodePos(1,1)), (1, 2, 'syntax_error')) + self.assertEquals(geterror('\n ?', NodePos(1,1)), (2, 1, 'syntax_error')) + def testNodePos(self): + def getnodepos(script, startpos): + root = parse(script, None, startpos) + self.assertEquals(root.kind, tok.LC) + var, = root.kids + self.assertEquals(var.kind, tok.VAR) + return var.start_pos() + self.assertEquals(getnodepos('var x;', None), NodePos(0,0)) + self.assertEquals(getnodepos(' var x;', None), NodePos(0,1)) + self.assertEquals(getnodepos('\n\n var x;', None), NodePos(2,1)) + self.assertEquals(getnodepos('var x;', NodePos(3,4)), NodePos(3,4)) + self.assertEquals(getnodepos(' var x;', NodePos(3,4)), NodePos(3,5)) + self.assertEquals(getnodepos('\n\n var x;', NodePos(3,4)), NodePos(5,1)) + def testComments(self): + def testcomment(comment, startpos, expectedpos): + root = parse(comment, None, startpos) + comment, = parsecomments(comment, root, startpos) + self.assertEquals(comment.start_pos(), expectedpos) + for comment in ('/*comment*/', '//comment'): + testcomment(comment, None, NodePos(0,0)) + testcomment(' %s' % comment, None, NodePos(0,1)) + testcomment('\n\n %s' % comment, None, NodePos(2,1)) + testcomment('%s' % comment, NodePos(3,4), NodePos(3,4)) + testcomment(' %s' % comment, NodePos(3,4), NodePos(3,5)) + testcomment('\n\n %s' % comment, NodePos(3,4), NodePos(5,1)) + if __name__ == '__main__': unittest.main() Modified: trunk/pyspidermonkey/pyspidermonkey.c =================================================================== --- trunk/pyspidermonkey/pyspidermonkey.c 2008-08-28 00:25:42 UTC (rev 230) +++ trunk/pyspidermonkey/pyspidermonkey.c 2008-08-28 04:34:11 UTC (rev 231) @@ -124,17 +124,44 @@ typedef struct JSContextData { PyObject* node_class; PyObject* error_callback; + long int first_lineno; + long int first_index; } JSContextData; +static long int +to_pyjsl_lineno(JSContextData* data, long int lineno) { + /* SpiderMonkey uses 1-based line numbers. */ + return lineno + data->first_lineno - 1; +} + +static long int +to_pyjsl_index(JSContextData* data, long int lineno, long int index) { + /* SpiderMonkey uses 1-based line numbers. */ + if (lineno - 1 == 0) + return index + data->first_index; + else + return index; +} + +static JSTokenPtr +to_pyjsl_pos(JSContextData* data, JSTokenPtr ptr) { + JSTokenPtr newptr = ptr; + newptr.index = to_pyjsl_index(data, ptr.lineno, ptr.index); + newptr.lineno = to_pyjsl_lineno(data, ptr.lineno); + return newptr; +} + static void error_reporter(JSContext* cx, const char* message, JSErrorReport* report) { JSContextData* data = JS_GetContextPrivate(cx); - long int line = report->lineno - 1; + long int line = to_pyjsl_lineno(data, report->lineno); long int col = -1; - if (report->uclinebuf) + if (report->uclinebuf) { col = report->uctokenptr - report->uclinebuf; + col = to_pyjsl_index(data, report->lineno, col); + } // TODO: Check return value (void)PyObject_CallFunction(data->error_callback, "lls", @@ -169,6 +196,7 @@ JSContextData* data = JS_GetContextPrivate(context); PyObject* pynode = NULL; PyObject* kids = NULL; + JSTokenPtr tokenptr; /* TODO: make sure no tuple item already exists */ @@ -192,13 +220,15 @@ goto fail; /* pass the position */ - if (PyObject_SetAttrString(pynode, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1) + tokenptr = to_pyjsl_pos(data, jsnode->pn_pos.begin); + if (PyObject_SetAttrString(pynode, "_start_line", Py_BuildValue("i", tokenptr.lineno)) == -1) goto fail; - if (PyObject_SetAttrString(pynode, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1) + if (PyObject_SetAttrString(pynode, "_start_col", Py_BuildValue("i", tokenptr.index)) == -1) goto fail; - if (PyObject_SetAttrString(pynode, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1) + tokenptr = to_pyjsl_pos(data, jsnode->pn_pos.end); + if (PyObject_SetAttrString(pynode, "_end_line", Py_BuildValue("i", tokenptr.lineno)) == -1) goto fail; - if (PyObject_SetAttrString(pynode, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1) + if (PyObject_SetAttrString(pynode, "_end_col", Py_BuildValue("i", tokenptr.index)) == -1) goto fail; if ((jsnode->pn_type == TOK_NAME || jsnode->pn_type == TOK_DOT || @@ -370,8 +400,11 @@ error = "encountered an unknown error"; /* validate arguments */ - if (!PyArg_ParseTuple(args, "sOO", &m.script, &m.ctx_data.node_class, &m.ctx_data.error_callback)) + if (!PyArg_ParseTuple(args, "sOOll", &m.script, &m.ctx_data.node_class, + &m.ctx_data.error_callback, &m.ctx_data.first_lineno, + &m.ctx_data.first_index)) { return NULL; + } if (!PyCallable_Check(m.ctx_data.node_class)) { PyErr_SetString(PyExc_ValueError, "\"node_class\" must be callable"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 00:25:44
|
Revision: 230 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=230&view=rev Author: matthiasmiller Date: 2008-08-28 00:25:42 +0000 (Thu, 28 Aug 2008) Log Message: ----------- improve pyjsl.lint.Scope's contract: * Outer-level scopes will never be associated with a node. * All inner-level scopes will always be associated with a node. Modified Paths: -------------- trunk/pyjsl/lint.py Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-28 00:18:44 UTC (rev 229) +++ trunk/pyjsl/lint.py 2008-08-28 00:25:42 UTC (rev 230) @@ -72,16 +72,20 @@ return (comment, keyword, parms) class Scope: - def __init__(self, node): - """ node may be None """ + """ Outer-level scopes will never be associated with a node. + Inner-level scopes will always be associated with a node. + """ + def __init__(self): self._parent = None self._kids = [] self._identifiers = {} self._references = [] - self._node = node + self._node = None def add_scope(self, node): - self._kids.append(Scope(node)) + assert not node is None + self._kids.append(Scope()) self._kids[-1]._parent = self + self._kids[-1]._node = node return self._kids[-1] def add_declaration(self, name, node): self._identifiers[name] = node @@ -157,22 +161,22 @@ child._find_unreferenced_and_undeclared(unreferenced, undeclared, is_in_with_scope) def find_scope(self, node): - if not self._node: - return None - for kid in self._kids: scope = kid.find_scope(node) if scope: return scope # Always add it to the outer scope. - if not self._parent or \ - (node.start_pos() >= self._node.start_pos() and \ + if not self._parent: + assert not self._node + return self + + # Conditionally add it to an inner scope. + assert self._node + if (node.start_pos() >= self._node.start_pos() and \ node.end_pos() <= self._node.end_pos()): return self - return None - def lint_files(paths, lint_error, conf=conf.Conf()): def lint_file(path): def import_script(import_path): @@ -258,7 +262,7 @@ # Cache empty results for this script. assert not script_cache script_cache['imports'] = set() - script_cache['scope'] = Scope(None) + script_cache['scope'] = Scope() # Report errors and quit. for pos, msg in parse_errors: @@ -321,7 +325,7 @@ assert not script_cache imports = script_cache['imports'] = set() - scope = script_cache['scope'] = Scope(root) + scope = script_cache['scope'] = Scope() # Push the scope/variable checks. visitation.make_visitors(visitors, [_get_scope_checks(scope, report)]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 00:18:46
|
Revision: 229 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=229&view=rev Author: matthiasmiller Date: 2008-08-28 00:18:44 +0000 (Thu, 28 Aug 2008) Log Message: ----------- pyjsl.lint.Scope's contract indicates that "node" may be None Modified Paths: -------------- trunk/pyjsl/lint.py Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-28 00:14:15 UTC (rev 228) +++ trunk/pyjsl/lint.py 2008-08-28 00:18:44 UTC (rev 229) @@ -128,7 +128,8 @@ (scope, name, node) ] """ - is_in_with_scope = is_in_with_scope or self._node.kind == tok.WITH + if self._node and self._node.kind == tok.WITH: + is_in_with_scope = True # Add all identifiers as unreferenced. Children scopes will remove # them if they are referenced. Variables need to be keyed by name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 00:14:17
|
Revision: 228 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=228&view=rev Author: matthiasmiller Date: 2008-08-28 00:14:15 +0000 (Thu, 28 Aug 2008) Log Message: ----------- unreachable_code: check for unreachable conditions in for loops and do..while loops Modified Paths: -------------- trunk/pyjsl/warnings.py trunk/tests/warnings/missing_break.js trunk/tests/warnings/unreachable_code.js Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-28 00:02:50 UTC (rev 227) +++ trunk/pyjsl/warnings.py 2008-08-28 00:14:15 UTC (rev 228) @@ -382,6 +382,23 @@ if not sibling.kind in (tok.VAR, tok.FUNCTION): raise LintWarning, sibling +@lookfor(tok.FOR) +def unreachable_code_(node): + # Warn if the for loop always exits. + preamble, code = node.kids + if preamble.kind == tok.RESERVED: + pre, condition, post = preamble.kids + if post: + if not None in _get_exit_points(code): + raise LintWarning, post + +@lookfor(tok.DO) +def unreachable_code__(node): + # Warn if the do..while loop always exits. + code, condition = node.kids + if not None in _get_exit_points(code): + raise LintWarning, condition + #TODO: @lookfor(tok.IF) def meaningless_block(node): condition, if_, else_ = node.kids Modified: trunk/tests/warnings/missing_break.js =================================================================== --- trunk/tests/warnings/missing_break.js 2008-08-28 00:02:50 UTC (rev 227) +++ trunk/tests/warnings/missing_break.js 2008-08-28 00:14:15 UTC (rev 228) @@ -94,7 +94,7 @@ case 9: /* test a break inside a loop */ - for (i = 0; i < 100; i++) { + for (;;) { break; } Modified: trunk/tests/warnings/unreachable_code.js =================================================================== --- trunk/tests/warnings/unreachable_code.js 2008-08-28 00:02:50 UTC (rev 227) +++ trunk/tests/warnings/unreachable_code.js 2008-08-28 00:14:15 UTC (rev 228) @@ -38,4 +38,27 @@ return 42; } } + + /* test unreachable statements in for loops */ + for (i = 0; i < 10; i++) { /*warning:unreachable_code*/ + if (i) + break; + else + return; + } + for (i = 0; i < 10; ) { + if (i) + break; + else + return; + } + + /* test unreachable statements in do..while loops. */ + do { + if (i) + break; + else + return; + } while (i); /*warning:unreachable_code*/ + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-28 00:02:53
|
Revision: 227 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=227&view=rev Author: matthiasmiller Date: 2008-08-28 00:02:50 +0000 (Thu, 28 Aug 2008) Log Message: ----------- improve code flow warnings -change _get_exit_points to return the actual nodes -change the no_return_value, anon_no_return_value, and unreachable_code warnings to ignore declarations Modified Paths: -------------- trunk/pyjsl/lint.py trunk/pyjsl/warnings.py trunk/tests/warnings/anon_no_return_value.js trunk/tests/warnings/missing_break.js trunk/tests/warnings/no_return_value.js trunk/tests/warnings/unreachable_code.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-27 16:11:25 UTC (rev 226) +++ trunk/pyjsl/lint.py 2008-08-28 00:02:50 UTC (rev 227) @@ -194,7 +194,8 @@ def _lint_script(script, script_cache, lint_error, conf, import_callback): def parse_error(row, col, msg): - if not msg in ('redeclared_var', 'var_hides_arg'): + if not msg in ('anon_no_return_value', 'no_return_value', + 'redeclared_var', 'var_hides_arg'): parse_errors.append((jsparse.NodePos(row, col), msg)) def report(node, errname): Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-27 16:11:25 UTC (rev 226) +++ trunk/pyjsl/warnings.py 2008-08-28 00:02:50 UTC (rev 227) @@ -69,7 +69,9 @@ 'dup_option_explicit': 'duplicate "option explicit" control comment', 'invalid_fallthru': 'unexpected "fallthru" control comment', 'invalid_pass': 'unexpected "pass" control comment', - 'want_assign_or_call': 'expected an assignment or function call' + 'want_assign_or_call': 'expected an assignment or function call', + 'no_return_value': 'function {0} does not always return a value', + 'anon_no_return_value': 'anonymous function does not always return value' } _visitors = [] @@ -94,15 +96,22 @@ return None def _get_exit_points(node): + """ Returns a set of exit points, which may be: + * None, indicating a code path with no specific exit point. + * a node of type tok.BREAK, tok.RETURN, tok.THROW. + """ if node.kind == tok.LC: - # Only if the last child contains it exit_points = set([None]) for kid in node.kids: - # "None" is only a valid exit point for the last statement. - if None in exit_points: - exit_points.remove(None) if kid: - exit_points |= _get_exit_points(kid) + # Merge in the kid's exit points. + kid_exit_points = _get_exit_points(kid) + exit_points |= kid_exit_points + + # Stop if the kid always exits. + if not None in kid_exit_points: + exit_points.discard(None) + break elif node.kind == tok.IF: # Only if both branches have an exit point cond_, if_, else_ = node.kids @@ -126,10 +135,9 @@ # Correct the "None" exit point. exit_points.remove(None) - # Check if the switch contained any break - if tok.BREAK in exit_points: - exit_points.remove(tok.BREAK) - exit_points.add(None) + # Convert "break" into None + exit_points = set(map(lambda node: node \ + if node and node.kind != tok.BREAK else None, exit_points)) # Check if the switch had a default case if not switch_has_default: @@ -139,13 +147,13 @@ if switch_has_final_fallthru: exit_points.add(None) elif node.kind == tok.BREAK: - exit_points = set([tok.BREAK]) + exit_points = set([node]) elif node.kind == tok.WITH: exit_points = _get_exit_points(node.kids[-1]) elif node.kind == tok.RETURN: - exit_points = set([tok.RETURN]) + exit_points = set([node]) elif node.kind == tok.THROW: - exit_points = set([tok.THROW]) + exit_points = set([node]) elif node.kind == tok.TRY: try_, catch_, finally_ = node.kids @@ -369,9 +377,10 @@ @lookfor(tok.BREAK, tok.CONTINUE, tok.RETURN, tok.THROW) def unreachable_code(node): - if node.parent.kind == tok.LC and \ - node.node_index != len(node.parent.kids)-1: - raise LintWarning, node.parent.kids[node.node_index+1] + if node.parent.kind == tok.LC: + for sibling in node.parent.kids[node.node_index+1:]: + if not sibling.kind in (tok.VAR, tok.FUNCTION): + raise LintWarning, sibling #TODO: @lookfor(tok.IF) def meaningless_block(node): @@ -446,6 +455,36 @@ return raise LintWarning, child +def _check_return_value(node): + def is_return_with_val(node): + return node and node.kind == tok.RETURN and node.kids[0] + def is_return_without_val(node): + return node and node.kind == tok.RETURN and not node.kids[0] + + node, = node.kids + assert node.kind == tok.LC + + exit_points = _get_exit_points(node) + if filter(is_return_with_val, exit_points): + # If the function returns a value, find all returns without a value. + returns = filter(is_return_without_val, exit_points) + returns.sort(key=lambda node: node.start_pos()) + if returns: + raise LintWarning, returns[0] + # Warn if the function sometimes exits naturally. + if None in exit_points: + raise LintWarning, node + +@lookfor(tok.FUNCTION) +def no_return_value(node): + if node.fn_name: + _check_return_value(node) + +@lookfor(tok.FUNCTION) +def anon_no_return_value(node): + if not node.fn_name: + _check_return_value(node) + @lookfor() def mismatch_ctrl_comments(node): pass Modified: trunk/tests/warnings/anon_no_return_value.js =================================================================== --- trunk/tests/warnings/anon_no_return_value.js 2008-08-27 16:11:25 UTC (rev 226) +++ trunk/tests/warnings/anon_no_return_value.js 2008-08-28 00:02:50 UTC (rev 227) @@ -9,10 +9,10 @@ var error2 = function(b) { if (b) { - return; + return; /*warning:anon_no_return_value*/ } else { - return ""; /*warning:anon_no_return_value*/ + return ""; } }; Modified: trunk/tests/warnings/missing_break.js =================================================================== --- trunk/tests/warnings/missing_break.js 2008-08-27 16:11:25 UTC (rev 226) +++ trunk/tests/warnings/missing_break.js 2008-08-28 00:02:50 UTC (rev 227) @@ -92,7 +92,13 @@ return i; } - default: + case 9: + /* test a break inside a loop */ + for (i = 0; i < 100; i++) { + break; + } + + default: /*warning:missing_break*/ break; } Modified: trunk/tests/warnings/no_return_value.js =================================================================== --- trunk/tests/warnings/no_return_value.js 2008-08-27 16:11:25 UTC (rev 226) +++ trunk/tests/warnings/no_return_value.js 2008-08-28 00:02:50 UTC (rev 227) @@ -9,10 +9,10 @@ function error2(b) { if (b) { - return; + return; /*warning:no_return_value*/ } else { - return ""; /*warning:no_return_value*/ + return ""; } } Modified: trunk/tests/warnings/unreachable_code.js =================================================================== --- trunk/tests/warnings/unreachable_code.js 2008-08-27 16:11:25 UTC (rev 226) +++ trunk/tests/warnings/unreachable_code.js 2008-08-28 00:02:50 UTC (rev 227) @@ -26,4 +26,16 @@ throw i; i -= 1; /*warning:unreachable_code*/ } + + function var_test() { + return undef; + var undef; + } + + function func_test() { + return fortytwo(); + function fortytwo() { + return 42; + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-27 16:11:36
|
Revision: 226 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=226&view=rev Author: matthiasmiller Date: 2008-08-27 16:11:25 +0000 (Wed, 27 Aug 2008) Log Message: ----------- unreferenced_identifier: add another test case Modified Paths: -------------- trunk/tests/warnings/unreferenced_identifier.js Modified: trunk/tests/warnings/unreferenced_identifier.js =================================================================== --- trunk/tests/warnings/unreferenced_identifier.js 2008-08-27 02:30:20 UTC (rev 225) +++ trunk/tests/warnings/unreferenced_identifier.js 2008-08-27 16:11:25 UTC (rev 226) @@ -72,6 +72,10 @@ tmp = ref_dec--; /*warning:inc_dec_within_stmt*/ tmp = -tmp; + /* Test named functions as references. */ + var fn = function ref_func() { return 42; }; /*warning:unreferenced_identifier*/ + fn(); + /* Test nested scopes. */ function get_callback(parm) { return function() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-27 02:30:23
|
Revision: 225 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=225&view=rev Author: matthiasmiller Date: 2008-08-27 02:30:20 +0000 (Wed, 27 Aug 2008) Log Message: ----------- tweak output of the --dump parameter Modified Paths: -------------- trunk/pyjsl/jsparse.py Modified: trunk/pyjsl/jsparse.py =================================================================== --- trunk/pyjsl/jsparse.py 2008-08-27 01:59:38 UTC (rev 224) +++ trunk/pyjsl/jsparse.py 2008-08-27 02:30:20 UTC (rev 225) @@ -12,6 +12,10 @@ [getattr(tok, prop) for prop in dir(tok)], ['tok.%s' % prop for prop in dir(tok)] )) +_op_names = dict(zip( + [getattr(op, prop) for prop in dir(op)], + ['op.%s' % prop for prop in dir(op)] +)) NodePos = pyspidermonkey.NodePos @@ -204,11 +208,19 @@ return pyspidermonkey.is_compilable_unit(script) def _dump_node(node, depth=0): - print '. '*depth, if node is None: - print '(none)' + print ' '*depth, + print '(None)' + print else: - print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos()) + print ' '*depth, + print '%s, %s' % (_tok_names[node.kind], _op_names[node.opcode]) + print ' '*depth, + print '%s - %s' % (node.start_pos(), node.end_pos()) + if hasattr(node, 'atom'): + print ' '*depth, + print 'atom: %s' % node.atom + print for node in node.kids: _dump_node(node, depth+1) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-27 01:59:41
|
Revision: 224 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=224&view=rev Author: matthiasmiller Date: 2008-08-27 01:59:38 +0000 (Wed, 27 Aug 2008) Log Message: ----------- fix for reading blank files Modified Paths: -------------- trunk/pyjsl/util.py Modified: trunk/pyjsl/util.py =================================================================== --- trunk/pyjsl/util.py 2008-08-27 01:58:41 UTC (rev 223) +++ trunk/pyjsl/util.py 2008-08-27 01:59:38 UTC (rev 224) @@ -12,7 +12,7 @@ def readfile(path): file = codecs.open(path, 'r', 'utf-8') contents = file.read() - if contents[0] == unicode(codecs.BOM_UTF8, 'utf8'): + if contents and contents[0] == unicode(codecs.BOM_UTF8, 'utf8'): contents = contents[1:] return contents This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-27 01:58:43
|
Revision: 223 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=223&view=rev Author: matthiasmiller Date: 2008-08-27 01:58:41 +0000 (Wed, 27 Aug 2008) Log Message: ----------- htmlparse: begin work on parsing HTML files Modified Paths: -------------- trunk/jsl.py Added Paths: ----------- trunk/pyjsl/htmlparse.py Modified: trunk/jsl.py =================================================================== --- trunk/jsl.py 2008-08-26 16:06:32 UTC (rev 222) +++ trunk/jsl.py 2008-08-27 01:58:41 UTC (rev 223) @@ -15,6 +15,7 @@ sys.path.append(setup.get_lib_path()) import pyjsl.conf +import pyjsl.htmlparse import pyjsl.jsparse import pyjsl.util import test @@ -130,7 +131,7 @@ if options.unittest: suite = unittest.TestSuite(); - for module in [pyjsl.jsparse, pyjsl.util]: + for module in [pyjsl.htmlparse, pyjsl.jsparse, pyjsl.util]: suite.addTest(unittest.findTestCases(module)) runner = unittest.TextTestRunner(verbosity=options.verbosity) Added: trunk/pyjsl/htmlparse.py =================================================================== --- trunk/pyjsl/htmlparse.py (rev 0) +++ trunk/pyjsl/htmlparse.py 2008-08-27 01:58:41 UTC (rev 223) @@ -0,0 +1,80 @@ +# vim: ts=4 sw=4 expandtab +import HTMLParser +import unittest + +import jsparse + +class _Parser(HTMLParser.HTMLParser): + def __init__(self): + HTMLParser.HTMLParser.__init__(self) + self._node_positions = jsparse.NodePositions('') + self._script = None + self._scripts = [] + + def handle_starttag(self, tag, attributes): + if tag.lower() == 'script' and not self._script: + offset = self._getoffset() + len(self.get_starttag_text()) + self._script = self._script or { + 'start': offset, + 'attributes': attributes + } + + def handle_endtag(self, tag): + if tag.lower() == 'script' and self._script: + start = self._script['start'] + end = self._getoffset() + script = self.rawdata[start:end] + if jsparse.is_compilable_unit(script): + attr = dict(self._script['attributes']) + self._scripts.append({ + 'script': script, + 'startoffset': start, + 'endoffset': end, + 'startpos': self._node_positions.from_offset(start), + 'endpos': self._node_positions.from_offset(end), + 'src': attr.get('src'), + 'type': attr.get('type') + }) + self._script = None + + def feed(self, data): + self._node_positions = jsparse.NodePositions(self.rawdata + data) + HTMLParser.HTMLParser.feed(self, data) + + def getscripts(self): + return self._scripts + + def _getnodepos(self): + line, col = self.getpos() + return jsparse.NodePos(line - 1, col) + + def _getoffset(self): + return self._node_positions.to_offset(self._getnodepos()) + +def findscripts(s): + parser = _Parser() + parser.feed(s) + parser.close() + return parser.getscripts() + +class TestHTMLParse(unittest.TestCase): + def testFindScript(self): + html = """ +<html><body> +<script src=test.js></script> +hi&b +a<script><!-- +var s = '<script></script>'; +--></script> +ok& +..</script> +ok& +</body> +</html> +""" + scripts = [x['script'] for x in findscripts(html)] + self.assertEquals(scripts, [ + "", + "<!--\nvar s = '<script></script>';\n-->" + ]) + Property changes on: trunk/pyjsl/htmlparse.py ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-26 16:06:36
|
Revision: 222 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=222&view=rev Author: matthiasmiller Date: 2008-08-26 16:06:32 +0000 (Tue, 26 Aug 2008) Log Message: ----------- unreferenced_identifier: handle x++ and x-- Modified Paths: -------------- trunk/pyjsl/lint.py trunk/tests/warnings/unreferenced_identifier.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-26 15:10:59 UTC (rev 221) +++ trunk/pyjsl/lint.py 2008-08-26 16:06:32 UTC (rev 222) @@ -142,7 +142,7 @@ resolved = self.resolve_identifier(name) if resolved: # Make sure this isn't an assignment. - if node.parent.kind == tok.ASSIGN and \ + if node.parent.kind in (tok.ASSIGN, tok.INC, tok.DEC) and \ node.node_index == 0 and \ node.parent.parent.kind == tok.SEMI: continue Modified: trunk/tests/warnings/unreferenced_identifier.js =================================================================== --- trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 15:10:59 UTC (rev 221) +++ trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 16:06:32 UTC (rev 222) @@ -59,6 +59,19 @@ var assigned_but_ref; (assigned_but_ref = callback)(); + /* Test increment and decrement. */ + var unref_inc; /*warning:unreferenced_identifier*/ + unref_inc++; + var unref_dec; /*warning:unreferenced_identifier*/ + unref_dec--; + + var tmp; + var ref_inc; + tmp = ref_inc++; /*warning:inc_dec_within_stmt*/ + var ref_dec; + tmp = ref_dec--; /*warning:inc_dec_within_stmt*/ + tmp = -tmp; + /* Test nested scopes. */ function get_callback(parm) { return function() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-26 15:11:01
|
Revision: 221 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=221&view=rev Author: matthiasmiller Date: 2008-08-26 15:10:59 +0000 (Tue, 26 Aug 2008) Log Message: ----------- want_assign_or_call: first cut at implementation Modified Paths: -------------- trunk/pyjsl/warnings.py trunk/tests/warnings/multiple_plus_minus.js Added Paths: ----------- trunk/tests/warnings/want_assign_or_call.js Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-26 13:54:31 UTC (rev 220) +++ trunk/pyjsl/warnings.py 2008-08-26 15:10:59 UTC (rev 221) @@ -68,7 +68,8 @@ 'partial_option_explicit': 'the "option explicit" control comment, if used, must be in the first script tag', 'dup_option_explicit': 'duplicate "option explicit" control comment', 'invalid_fallthru': 'unexpected "fallthru" control comment', - 'invalid_pass': 'unexpected "pass" control comment' + 'invalid_pass': 'unexpected "pass" control comment', + 'want_assign_or_call': 'expected an assignment or function call' } _visitors = [] @@ -426,6 +427,25 @@ if util.isidentifier(node.atom): raise LintWarning, node +@lookfor(tok.SEMI) +def want_assign_or_call(node): + child, = node.kids + # Ignore empty statements. + if not child: + return + # NOTE: Don't handle comma-separated statements. + if child.kind in (tok.ASSIGN, tok.INC, tok.DEC, tok.DELETE, tok.COMMA): + return + # Ignore function calls. + if child.kind == tok.LP and child.opcode == op.CALL: + return + # Allow new function() { } as statements. + if child.kind == tok.NEW: + grandchild, = child.kids + if grandchild.kind == tok.FUNCTION: + return + raise LintWarning, child + @lookfor() def mismatch_ctrl_comments(node): pass Modified: trunk/tests/warnings/multiple_plus_minus.js =================================================================== --- trunk/tests/warnings/multiple_plus_minus.js 2008-08-26 13:54:31 UTC (rev 220) +++ trunk/tests/warnings/multiple_plus_minus.js 2008-08-26 15:10:59 UTC (rev 221) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-want_assign_or_call*/ function multiple_plus_minus() { var i, j; i = 0; Added: trunk/tests/warnings/want_assign_or_call.js =================================================================== --- trunk/tests/warnings/want_assign_or_call.js (rev 0) +++ trunk/tests/warnings/want_assign_or_call.js 2008-08-26 15:10:59 UTC (rev 221) @@ -0,0 +1,25 @@ +function want_assign_or_call() { + var a; + a; /*warning:want_assign_or_call*/ + a++; + a--; + a /= 2; + a %= 4; + a >>= 3; + a << 2; /*warning:want_assign_or_call*/ + + new function() { + }; + + function test() { + } + + function() { /*warning:want_assign_or_call*/ + return 42; + } + + delete a; + + a.b(); +} + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-26 13:54:33
|
Revision: 220 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=220&view=rev Author: matthiasmiller Date: 2008-08-26 13:54:31 +0000 (Tue, 26 Aug 2008) Log Message: ----------- fix traceback with syntax errors Modified Paths: -------------- trunk/pyjsl/lint.py Added Paths: ----------- trunk/tests/errors/syntax_error.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-26 03:50:14 UTC (rev 219) +++ trunk/pyjsl/lint.py 2008-08-26 13:54:31 UTC (rev 220) @@ -245,17 +245,26 @@ return lint_error(pos.line, pos.col, errname) parse_errors = [] - root = jsparse.parse(script, parse_error) - if root: - comments = jsparse.parsecomments(script, root) - else: - comments = [] ignores = [] - start_ignore = None declares = [] import_paths = [] fallthrus = [] passes = [] + + root = jsparse.parse(script, parse_error) + if not root: + # Cache empty results for this script. + assert not script_cache + script_cache['imports'] = set() + script_cache['scope'] = Scope(None) + + # Report errors and quit. + for pos, msg in parse_errors: + _report(pos, msg, False) + return + + comments = jsparse.parsecomments(script, root) + start_ignore = None for comment in comments: cc = _parse_control_comment(comment) if cc: @@ -316,8 +325,7 @@ visitation.make_visitors(visitors, [_get_scope_checks(scope, report)]) # kickoff! - if root: - _lint_node(root, visitors) + _lint_node(root, visitors) for fallthru in fallthrus: report(fallthru, 'invalid_fallthru') Added: trunk/tests/errors/syntax_error.js =================================================================== --- trunk/tests/errors/syntax_error.js (rev 0) +++ trunk/tests/errors/syntax_error.js 2008-08-26 13:54:31 UTC (rev 220) @@ -0,0 +1,4 @@ +function syntax_error() { + &; /*warning:syntax_error*/ +} + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-26 03:50:20
|
Revision: 219 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=219&view=rev Author: matthiasmiller Date: 2008-08-26 03:50:14 +0000 (Tue, 26 Aug 2008) Log Message: ----------- unreferenced_identifier: by default, disable for tests to reduce noise Modified Paths: -------------- trunk/test.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/assign_to_function_call.js trunk/tests/warnings/duplicate_case_in_switch.js trunk/tests/warnings/inc_dec_within_stmt-ignore.js trunk/tests/warnings/inc_dec_within_stmt.js trunk/tests/warnings/leading_decimal_point.js trunk/tests/warnings/misplaced_regex.js trunk/tests/warnings/missing_break.js trunk/tests/warnings/missing_default_case.js trunk/tests/warnings/missing_semicolon.js trunk/tests/warnings/no_return_value.js trunk/tests/warnings/octal_number.js trunk/tests/warnings/parseint_missing_radix.js trunk/tests/warnings/redeclared_var.js trunk/tests/warnings/trailing_comma_in_array.js trunk/tests/warnings/trailing_decimal_point.js trunk/tests/warnings/unreferenced_identifier.js trunk/tests/warnings/useless_quotes.js trunk/tests/warnings/var_hides_arg.js Modified: trunk/test.py =================================================================== --- trunk/test.py 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/test.py 2008-08-26 03:50:14 UTC (rev 219) @@ -4,6 +4,12 @@ import pyjsl.conf import pyjsl.lint +_DEFAULT_CONF = """ +# This warning triggers a lot of warnings in many of the tests, so only enable +# it when specifically testing it. +-unreferenced_identifier +""" + class TestError(Exception): pass @@ -11,6 +17,7 @@ regexp = re.compile(r"/\*conf:([^*]*)\*/") text = '\n'.join(regexp.findall(script)) conf = pyjsl.conf.Conf() + conf.loadtext(_DEFAULT_CONF) conf.loadtext(text) return conf Modified: trunk/tests/control_comments/declare.js =================================================================== --- trunk/tests/control_comments/declare.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/control_comments/declare.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*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-26 03:32:35 UTC (rev 218) +++ trunk/tests/control_comments/option_explicit-with.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*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-26 03:32:35 UTC (rev 218) +++ trunk/tests/control_comments/option_explicit.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*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-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/ambiguous_newline.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*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-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/anon_no_return_value.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function anon_no_return_value() { var error1 = function(b) { if (b) Modified: trunk/tests/warnings/assign_to_function_call.js =================================================================== --- trunk/tests/warnings/assign_to_function_call.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/assign_to_function_call.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function assign_to_function_call() { var o; var s; Modified: trunk/tests/warnings/duplicate_case_in_switch.js =================================================================== --- trunk/tests/warnings/duplicate_case_in_switch.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/duplicate_case_in_switch.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function duplicate_case_in_switch() { var i, o, s; Modified: trunk/tests/warnings/inc_dec_within_stmt-ignore.js =================================================================== --- trunk/tests/warnings/inc_dec_within_stmt-ignore.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/inc_dec_within_stmt-ignore.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function inc_dec_within_stmt() { var x; do { Modified: trunk/tests/warnings/inc_dec_within_stmt.js =================================================================== --- trunk/tests/warnings/inc_dec_within_stmt.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/inc_dec_within_stmt.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function inc_dec_within_stmt() { var i, s; Modified: trunk/tests/warnings/leading_decimal_point.js =================================================================== --- trunk/tests/warnings/leading_decimal_point.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/leading_decimal_point.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function leading_decimal_point() { var i; Modified: trunk/tests/warnings/misplaced_regex.js =================================================================== --- trunk/tests/warnings/misplaced_regex.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/misplaced_regex.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*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-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/missing_break.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function missing_break() { var i, o, s; Modified: trunk/tests/warnings/missing_default_case.js =================================================================== --- trunk/tests/warnings/missing_default_case.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/missing_default_case.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function missing_default_case() { var i, s; Modified: trunk/tests/warnings/missing_semicolon.js =================================================================== --- trunk/tests/warnings/missing_semicolon.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/missing_semicolon.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,7 +1,7 @@ /*jsl:option explicit*/ function missing_semicolon() { /* missing semicolon after return */ - function MissingSemicolonOnReturnStatement() { /*warning:unreferenced_identifier*/ + function MissingSemicolonOnReturnStatement() { return 0 } /*warning:missing_semicolon*/ Modified: trunk/tests/warnings/no_return_value.js =================================================================== --- trunk/tests/warnings/no_return_value.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/no_return_value.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function no_return_value() { function error1(b) { if (b) Modified: trunk/tests/warnings/octal_number.js =================================================================== --- trunk/tests/warnings/octal_number.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/octal_number.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function octal_number() { var i; i = 010; /*warning:octal_number*/ Modified: trunk/tests/warnings/parseint_missing_radix.js =================================================================== --- trunk/tests/warnings/parseint_missing_radix.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/parseint_missing_radix.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function parseint_missing_radix() { var i; Modified: trunk/tests/warnings/redeclared_var.js =================================================================== --- trunk/tests/warnings/redeclared_var.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/redeclared_var.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function redeclared_var() { var duplicate; var duplicate; /*warning:redeclared_var*/ Modified: trunk/tests/warnings/trailing_comma_in_array.js =================================================================== --- trunk/tests/warnings/trailing_comma_in_array.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/trailing_comma_in_array.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function trailing_comma_in_array() { var a; Modified: trunk/tests/warnings/trailing_decimal_point.js =================================================================== --- trunk/tests/warnings/trailing_decimal_point.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/trailing_decimal_point.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*jsl:option explicit*/ -/*conf:-unreferenced_identifier*/ function trailing_decimal_point() { var i; Modified: trunk/tests/warnings/unreferenced_identifier.js =================================================================== --- trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,3 +1,6 @@ +/* The tests disable this warning by default becaues of noise. Enable it. */ +/*conf:+unreferenced_identifier*/ + /* outer-level functions shouldn't warn */ var unreferenced_global; function unreferenced_identifier() { Modified: trunk/tests/warnings/useless_quotes.js =================================================================== --- trunk/tests/warnings/useless_quotes.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/useless_quotes.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,4 +1,3 @@ -/*conf:-unreferenced_identifier*/ function useless_quotes() { var o = { 'key': 1 /*warning:useless_quotes*/ Modified: trunk/tests/warnings/var_hides_arg.js =================================================================== --- trunk/tests/warnings/var_hides_arg.js 2008-08-26 03:32:35 UTC (rev 218) +++ trunk/tests/warnings/var_hides_arg.js 2008-08-26 03:50:14 UTC (rev 219) @@ -1,5 +1,4 @@ /*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. |
From: <mat...@us...> - 2008-08-26 03:32:40
|
Revision: 218 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=218&view=rev Author: matthiasmiller Date: 2008-08-26 03:32:35 +0000 (Tue, 26 Aug 2008) Log Message: ----------- unreferenced_identifier: improve warning to ignore variable assignments Modified Paths: -------------- trunk/pyjsl/lint.py trunk/tests/warnings/assign_to_function_call.js trunk/tests/warnings/duplicate_case_in_switch.js trunk/tests/warnings/inc_dec_within_stmt-ignore.js trunk/tests/warnings/leading_decimal_point.js trunk/tests/warnings/missing_default_case.js trunk/tests/warnings/octal_number.js trunk/tests/warnings/parseint_missing_radix.js trunk/tests/warnings/trailing_comma_in_array.js trunk/tests/warnings/trailing_decimal_point.js trunk/tests/warnings/unreferenced_identifier.js trunk/tests/warnings/useless_quotes.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/pyjsl/lint.py 2008-08-26 03:32:35 UTC (rev 218) @@ -141,6 +141,11 @@ for name, node in self._references: resolved = self.resolve_identifier(name) if resolved: + # Make sure this isn't an assignment. + if node.parent.kind == tok.ASSIGN and \ + node.node_index == 0 and \ + node.parent.parent.kind == tok.SEMI: + continue unreferenced.pop((resolved[0], name), None) else: # with statements cannot have undeclared identifiers. Modified: trunk/tests/warnings/assign_to_function_call.js =================================================================== --- trunk/tests/warnings/assign_to_function_call.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/assign_to_function_call.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function assign_to_function_call() { var o; var s; Modified: trunk/tests/warnings/duplicate_case_in_switch.js =================================================================== --- trunk/tests/warnings/duplicate_case_in_switch.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/duplicate_case_in_switch.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function duplicate_case_in_switch() { var i, o, s; Modified: trunk/tests/warnings/inc_dec_within_stmt-ignore.js =================================================================== --- trunk/tests/warnings/inc_dec_within_stmt-ignore.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/inc_dec_within_stmt-ignore.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function inc_dec_within_stmt() { var x; do { Modified: trunk/tests/warnings/leading_decimal_point.js =================================================================== --- trunk/tests/warnings/leading_decimal_point.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/leading_decimal_point.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function leading_decimal_point() { var i; Modified: trunk/tests/warnings/missing_default_case.js =================================================================== --- trunk/tests/warnings/missing_default_case.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/missing_default_case.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function missing_default_case() { var i, s; Modified: trunk/tests/warnings/octal_number.js =================================================================== --- trunk/tests/warnings/octal_number.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/octal_number.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function octal_number() { var i; i = 010; /*warning:octal_number*/ Modified: trunk/tests/warnings/parseint_missing_radix.js =================================================================== --- trunk/tests/warnings/parseint_missing_radix.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/parseint_missing_radix.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function parseint_missing_radix() { var i; Modified: trunk/tests/warnings/trailing_comma_in_array.js =================================================================== --- trunk/tests/warnings/trailing_comma_in_array.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/trailing_comma_in_array.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function trailing_comma_in_array() { var a; Modified: trunk/tests/warnings/trailing_decimal_point.js =================================================================== --- trunk/tests/warnings/trailing_decimal_point.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/trailing_decimal_point.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,4 +1,5 @@ /*jsl:option explicit*/ +/*conf:-unreferenced_identifier*/ function trailing_decimal_point() { var i; Modified: trunk/tests/warnings/unreferenced_identifier.js =================================================================== --- trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/unreferenced_identifier.js 2008-08-26 03:32:35 UTC (rev 218) @@ -35,6 +35,7 @@ catch(err) { can = false; /* ...but maybe not! */ } + can = !can; /* Test a with statement. */ var withobj = {}; @@ -46,6 +47,15 @@ prop_b = innerval; } + /* Test assignments. */ + var assigned_but_unref; /*warning:unreferenced_identifier*/ + assigned_but_unref = 42; + + function callback() { + } + var assigned_but_ref; + (assigned_but_ref = callback)(); + /* Test nested scopes. */ function get_callback(parm) { return function() { Modified: trunk/tests/warnings/useless_quotes.js =================================================================== --- trunk/tests/warnings/useless_quotes.js 2008-08-26 03:11:02 UTC (rev 217) +++ trunk/tests/warnings/useless_quotes.js 2008-08-26 03:32:35 UTC (rev 218) @@ -1,3 +1,4 @@ +/*conf:-unreferenced_identifier*/ function useless_quotes() { var o = { 'key': 1 /*warning:useless_quotes*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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. |
From: <mat...@us...> - 2008-08-24 00:39:23
|
Revision: 216 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=216&view=rev Author: matthiasmiller Date: 2008-08-24 00:39:17 +0000 (Sun, 24 Aug 2008) Log Message: ----------- silence warning Modified Paths: -------------- trunk/tests/path_resolution/is_a_file_not_dir.js Modified: trunk/tests/path_resolution/is_a_file_not_dir.js =================================================================== --- trunk/tests/path_resolution/is_a_file_not_dir.js 2008-08-24 00:37:04 UTC (rev 215) +++ trunk/tests/path_resolution/is_a_file_not_dir.js 2008-08-24 00:39:17 UTC (rev 216) @@ -1,2 +1,2 @@ /*conf:+process file/ */ -/*conf_error:unable to resolve path: file/*/ +/*conf_error:unable to resolve path: file/*/ /*warning:nested_comment*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-24 00:37:06
|
Revision: 215 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=215&view=rev Author: matthiasmiller Date: 2008-08-24 00:37:04 +0000 (Sun, 24 Aug 2008) Log Message: ----------- useless_quotes: only warn if the text would be syntactically valid Modified Paths: -------------- trunk/jsl.py trunk/pyjsl/lint.py trunk/pyjsl/util.py trunk/pyjsl/warnings.py trunk/tests/warnings/ambiguous_newline.js Modified: trunk/jsl.py =================================================================== --- trunk/jsl.py 2008-08-23 23:58:12 UTC (rev 214) +++ trunk/jsl.py 2008-08-24 00:37:04 UTC (rev 215) @@ -129,8 +129,12 @@ profile_func = profile_enabled if options.unittest: + suite = unittest.TestSuite(); + for module in [pyjsl.jsparse, pyjsl.util]: + suite.addTest(unittest.findTestCases(module)) + runner = unittest.TextTestRunner(verbosity=options.verbosity) - runner.run(unittest.findTestCases(pyjsl.jsparse)) + runner.run(suite) if options.test: profile_func(run_tests) Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-23 23:58:12 UTC (rev 214) +++ trunk/pyjsl/lint.py 2008-08-24 00:37:04 UTC (rev 215) @@ -29,8 +29,6 @@ 'arguments', 'undefined' ]) -_identifier = re.compile('^[A-Za-z_$][A-Za-z0-9_$]*$') - def _find_function(node): while node and node.kind != tok.FUNCTION: node = node.parent @@ -222,7 +220,7 @@ if cc: node, keyword, parms = cc if keyword == 'declare': - if not _identifier.match(parms): + if not util.isidentifier(parms): report(node, 'jsl_cc_not_understood') else: declares.append((parms, node)) Modified: trunk/pyjsl/util.py =================================================================== --- trunk/pyjsl/util.py 2008-08-23 23:58:12 UTC (rev 214) +++ trunk/pyjsl/util.py 2008-08-24 00:37:04 UTC (rev 215) @@ -1,7 +1,14 @@ # vim: ts=4 sw=4 expandtab import codecs import os.path +import re +import unittest +_identifier = re.compile('^[A-Za-z_$][A-Za-z0-9_$]*$') + +def isidentifier(text): + return _identifier.match(text) + def readfile(path): file = codecs.open(path, 'r', 'utf-8') contents = file.read() @@ -15,3 +22,14 @@ path = os.path.normpath(path) return path +class TestUtil(unittest.TestCase): + def testIdentifier(self): + assert not isidentifier('') + assert not isidentifier('0a') + assert not isidentifier('a b') + assert isidentifier('a') + assert isidentifier('$0') + +if __name__ == '__main__': + unittest.main() + Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-23 23:58:12 UTC (rev 214) +++ trunk/pyjsl/warnings.py 2008-08-24 00:37:04 UTC (rev 215) @@ -18,6 +18,7 @@ import sys import types +import util import visitation from pyspidermonkey import tok, op @@ -420,7 +421,9 @@ @lookfor(tok.STRING) def useless_quotes(node): if node.node_index == 0 and node.parent.kind == tok.COLON: - raise LintWarning, node + # Only warn if the quotes could safely be removed. + if util.isidentifier(node.atom): + raise LintWarning, node @lookfor() def mismatch_ctrl_comments(node): Modified: trunk/tests/warnings/ambiguous_newline.js =================================================================== --- trunk/tests/warnings/ambiguous_newline.js 2008-08-23 23:58:12 UTC (rev 214) +++ trunk/tests/warnings/ambiguous_newline.js 2008-08-24 00:37:04 UTC (rev 215) @@ -185,8 +185,8 @@ /* legal */ o = { - 'one': 1, - 'two': 2 + one: 1, + two: 2 }; /* legal */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-23 23:58:16
|
Revision: 214 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=214&view=rev Author: matthiasmiller Date: 2008-08-23 23:58:12 +0000 (Sat, 23 Aug 2008) Log Message: ----------- first cut at supporting jsl:pass Modified Paths: -------------- trunk/pyjsl/lint.py trunk/pyjsl/warnings.py trunk/spidermonkey/src/jsparse.c trunk/test.py trunk/tests/path_resolution/asterisk.js trunk/tests/path_resolution/is_a_file_not_dir.js trunk/tests/path_resolution/not_a_dir.js trunk/tests/path_resolution/not_a_file.js trunk/tests/path_resolution/question_mark.js Added Paths: ----------- trunk/tests/control_comments/invalid_pass.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/pyjsl/lint.py 2008-08-23 23:58:12 UTC (rev 214) @@ -156,9 +156,16 @@ def _lint_script(script, script_cache, lint_error, conf, import_callback): def parse_error(row, col, msg): if not msg in ('redeclared_var', 'var_hides_arg'): - parse_errors.append((jsparse.NodePos(row, col), msg)) + parse_errors.append((jsparse.NodePos(row, col), msg)) def report(node, errname): + if errname == 'empty_statement' and node.kind == tok.LC: + for pass_ in passes: + if pass_.start_pos() > node.start_pos() and \ + pass_.end_pos() < node.end_pos(): + passes.remove(pass_) + return + if errname == 'missing_break': # Find the end of the previous case/default and the beginning of # the next case/default. @@ -209,6 +216,7 @@ declares = [] import_paths = [] fallthrus = [] + passes = [] for comment in comments: cc = _parse_control_comment(comment) if cc: @@ -236,6 +244,8 @@ import_paths.append(parms) elif keyword == 'fallthru': fallthrus.append(node) + elif keyword == 'pass': + passes.append(node) else: if comment.opcode == 'c_comment': if '/*' in comment.atom or comment.atom.endswith('/'): @@ -272,6 +282,8 @@ for fallthru in fallthrus: report(fallthru, 'invalid_fallthru') + for fallthru in passes: + report(fallthru, 'invalid_pass') # Process imports by copying global declarations into the universal scope. imports |= set(conf['declarations']) Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/pyjsl/warnings.py 2008-08-23 23:58:12 UTC (rev 214) @@ -65,7 +65,8 @@ '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', 'dup_option_explicit': 'duplicate "option explicit" control comment', - 'invalid_fallthru': 'unexpected "fallthru" control comment' + 'invalid_fallthru': 'unexpected "fallthru" control comment', + 'invalid_pass': 'unexpected "pass" control comment' } _visitors = [] Modified: trunk/spidermonkey/src/jsparse.c =================================================================== --- trunk/spidermonkey/src/jsparse.c 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/spidermonkey/src/jsparse.c 2008-08-23 23:58:12 UTC (rev 214) @@ -1519,7 +1519,9 @@ if (tt == TOK_ERROR) return NULL; - pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; + /* Set the LC's end position to the start of the RC. The stream is + * guaranteed to have a lookahead because of the peek above. */ + pn->pn_pos.end = ts->tokens[(ts->cursor+ts->lookahead) & NTOKENS_MASK].pos.begin; return pn; } Modified: trunk/test.py =================================================================== --- trunk/test.py 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/test.py 2008-08-23 23:58:12 UTC (rev 214) @@ -24,7 +24,7 @@ for i in range(0, len(lines)): for warning in regexp.findall(lines[i]): # TODO: implement these - unimpl_warnings = ('ambiguous_newline', 'dup_option_explicit', 'invalid_pass', + unimpl_warnings = ('ambiguous_newline', 'dup_option_explicit', 'missing_semicolon' ) if not warning in unimpl_warnings: Added: trunk/tests/control_comments/invalid_pass.js =================================================================== --- trunk/tests/control_comments/invalid_pass.js (rev 0) +++ trunk/tests/control_comments/invalid_pass.js 2008-08-23 23:58:12 UTC (rev 214) @@ -0,0 +1,2 @@ +/*jsl:option explicit*/ +/*jsl:pass*/ /*warning:invalid_pass*/ Modified: trunk/tests/path_resolution/asterisk.js =================================================================== --- trunk/tests/path_resolution/asterisk.js 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/tests/path_resolution/asterisk.js 2008-08-23 23:58:12 UTC (rev 214) @@ -1,3 +1,2 @@ /*conf:+process unknown_dir/a*b */ /*conf_error:unable to resolve path: unknown_dir/a*b*/ -/*jsl:pass*/ Modified: trunk/tests/path_resolution/is_a_file_not_dir.js =================================================================== --- trunk/tests/path_resolution/is_a_file_not_dir.js 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/tests/path_resolution/is_a_file_not_dir.js 2008-08-23 23:58:12 UTC (rev 214) @@ -1,3 +1,2 @@ /*conf:+process file/ */ /*conf_error:unable to resolve path: file/*/ -/*jsl:pass*/ Modified: trunk/tests/path_resolution/not_a_dir.js =================================================================== --- trunk/tests/path_resolution/not_a_dir.js 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/tests/path_resolution/not_a_dir.js 2008-08-23 23:58:12 UTC (rev 214) @@ -1,3 +1,2 @@ /*conf:+process not_a_dir*/ /*conf_error:unable to resolve path: not_a_dir*/ -/*jsl:pass*/ Modified: trunk/tests/path_resolution/not_a_file.js =================================================================== --- trunk/tests/path_resolution/not_a_file.js 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/tests/path_resolution/not_a_file.js 2008-08-23 23:58:12 UTC (rev 214) @@ -1,3 +1,2 @@ /*conf:+process not_a_file*/ /*conf_error:unable to resolve path: not_a_file*/ -/*jsl:pass*/ Modified: trunk/tests/path_resolution/question_mark.js =================================================================== --- trunk/tests/path_resolution/question_mark.js 2008-08-23 23:14:10 UTC (rev 213) +++ trunk/tests/path_resolution/question_mark.js 2008-08-23 23:58:12 UTC (rev 214) @@ -1,3 +1,2 @@ /*conf:+process unknown_dir/a?b */ /*conf_error:unable to resolve path: unknown_dir/a?b*/ -/*jsl:pass*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mat...@us...> - 2008-08-23 23:14:12
|
Revision: 213 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=213&view=rev Author: matthiasmiller Date: 2008-08-23 23:14:10 +0000 (Sat, 23 Aug 2008) Log Message: ----------- first cut at implementing fallthru Modified Paths: -------------- trunk/pyjsl/lint.py trunk/pyjsl/warnings.py trunk/tests/warnings/missing_default_case.js Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-08-23 22:32:48 UTC (rev 212) +++ trunk/pyjsl/lint.py 2008-08-23 23:14:10 UTC (rev 213) @@ -159,6 +159,29 @@ parse_errors.append((jsparse.NodePos(row, col), msg)) def report(node, errname): + if errname == 'missing_break': + # Find the end of the previous case/default and the beginning of + # the next case/default. + assert node.kind in (tok.CASE, tok.DEFAULT) + prevnode = node.parent.kids[node.node_index-1] + expectedfallthru = prevnode.end_pos(), node.start_pos() + elif errname == 'missing_break_for_last_case': + # Find the end of the current case/default and the end of the + # switch. + assert node.parent.kind == tok.LC + expectedfallthru = node.end_pos(), node.parent.end_pos() + else: + expectedfallthru = None + + if expectedfallthru: + start, end = expectedfallthru + for fallthru in fallthrus: + # Look for a fallthru between the end of the current case or + # default statement and the beginning of the next token. + if fallthru.start_pos() > start and fallthru.end_pos() < end: + fallthrus.remove(fallthru) + return + _report(node.start_pos(), errname, True) def _report(pos, errname, require_key): @@ -185,6 +208,7 @@ start_ignore = None declares = [] import_paths = [] + fallthrus = [] for comment in comments: cc = _parse_control_comment(comment) if cc: @@ -210,6 +234,8 @@ report(node, 'jsl_cc_not_understood') else: import_paths.append(parms) + elif keyword == 'fallthru': + fallthrus.append(node) else: if comment.opcode == 'c_comment': if '/*' in comment.atom or comment.atom.endswith('/'): @@ -244,6 +270,9 @@ if root: _lint_node(root, visitors) + for fallthru in fallthrus: + report(fallthru, 'invalid_fallthru') + # Process imports by copying global declarations into the universal scope. imports |= set(conf['declarations']) imports |= _globals Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-08-23 22:32:48 UTC (rev 212) +++ trunk/pyjsl/warnings.py 2008-08-23 23:14:10 UTC (rev 213) @@ -65,6 +65,7 @@ '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', 'dup_option_explicit': 'duplicate "option explicit" control comment', + 'invalid_fallthru': 'unexpected "fallthru" control comment' } _visitors = [] Modified: trunk/tests/warnings/missing_default_case.js =================================================================== --- trunk/tests/warnings/missing_default_case.js 2008-08-23 22:32:48 UTC (rev 212) +++ trunk/tests/warnings/missing_default_case.js 2008-08-23 23:14:10 UTC (rev 213) @@ -8,10 +8,10 @@ return 1; } - /* ambivalence - allow fallthru but don't enforce it */ + /* ambivalence - fallthru is meaningless */ switch (i) { case 2: - /*jsl:fallthru*/ + /*jsl:fallthru*/ /*warning:invalid_fallthru*/ case 3: s += 1; break; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |