diff options
author | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-22 16:34:13 +0000 |
---|---|---|
committer | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-22 16:34:13 +0000 |
commit | caff0c340f4abbe36fb5ad24f2c55811003bea8d (patch) | |
tree | ca34d1223453509e12183a9f50a1862d0ca127e0 /ppapi/generators | |
parent | 05d7cf8c9bbf1585224fe839184fbc5d9f9b70dd (diff) | |
download | chromium_src-caff0c340f4abbe36fb5ad24f2c55811003bea8d.zip chromium_src-caff0c340f4abbe36fb5ad24f2c55811003bea8d.tar.gz chromium_src-caff0c340f4abbe36fb5ad24f2c55811003bea8d.tar.bz2 |
Adding linter for IDL
Removing current warnings from parser and create a new file
which will traverse AST after it is built looking for possible
issues.
Also includes minor comment cleanup for visitor class on which
the linter is based.
TEST= python idl_parser.py
BUG= http://code.google.com/p/chromium/issues/detail?id=76271
R= sehr@google.com
Review URL: http://codereview.chromium.org/7468012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93655 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/generators')
-rw-r--r-- | ppapi/generators/idl_lint.py | 120 | ||||
-rw-r--r-- | ppapi/generators/idl_parser.py | 26 | ||||
-rw-r--r-- | ppapi/generators/idl_visitor.py | 14 |
3 files changed, 132 insertions, 28 deletions
diff --git a/ppapi/generators/idl_lint.py b/ppapi/generators/idl_lint.py new file mode 100644 index 0000000..c6ef89e --- /dev/null +++ b/ppapi/generators/idl_lint.py @@ -0,0 +1,120 @@ +#!/usr/bin/python +# +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Lint for IDL """ + +import os +import sys + +from idl_log import ErrOut, InfoOut, WarnOut +from idl_node import IDLAttribute, IDLNode +from idl_ast import IDLAst +from idl_option import GetOption, Option, ParseOptions +from idl_outfile import IDLOutFile +from idl_visitor import IDLVisitor + + +Option('wcomment', 'Disable warning for missing comment.') +Option('wenum', 'Disable warning for missing enum value.') +Option('winline', 'Disable warning for inline blocks.') +Option('wparam', 'Disable warning for missing [in|out|inout] on param.') +Option('wpass', 'Disable warning for mixed passByValue and returnByValue.') + +# +# IDLLinter +# +# Once the AST is build, we need to resolve the namespace and version +# information. +# +class IDLLinter(IDLVisitor): + def VisitFilter(self, node, data): + __pychecker__ = 'unusednames=node,data' + return not node.IsA('Comment', 'Copyright') + + def Arrive(self, node, errors): + __pychecker__ = 'unusednames=node,errors' + warnings = 0 + if node.IsA('Interface', 'Member', 'Struct', 'Enum', 'EnumItem', 'Typedef'): + comments = node.GetListOf('Comment') + if not comments and not node.GetProperty('wcomment'): + node.Warning('Expecting a comment.') + warnings += 1 + + if node.IsA('Struct', 'Typedef') and not node.GetProperty('wpass'): + if node.GetProperty('passByValue'): + pbv = 'is' + else: + pbv = 'is not' + if node.GetProperty('returnByValue'): + ret = 'is' + else: + ret = 'is not' + if pbv != ret: + node.Warning('%s passByValue but %s returnByValue.' % (pbv, ret)) + warnings += 1 + + if node.IsA('EnumItem'): + if not node.GetProperty('VALUE') and not node.GetProperty('wenum'): + node.Warning('Expecting value for enumeration.') + warnings += 1 + + if node.IsA('Interface'): + if not node.GetLabel(): + node.Warning('Expecting label.') + warnings += 1 + macro = node.GetProperty('macro') + if macro: + node.Warning('Interface name inconsistent: %s' % macro) + warnings += 1 + + if node.IsA('Inline') and not node.GetProperty('winline'): + inline_type = node.GetProperty('NAME') + node.parent.Warning('Requires an inline %s block.' % inline_type) + warnings += 1 + + if node.IsA('Callspec'): + out = False + for arg in node.GetListOf('Param'): + if arg.GetProperty('out'): + out = True + if arg.GetProperty('in') and out: + arg.Warning('[in] parameter after [out] parameter') + warnings += 1 + + if node.IsA('Param') and not node.GetProperty('wparam'): + found = False; + for form in ['in', 'inout', 'out']: + if node.GetProperty(form): found = True + if not found: + node.Warning('Missing argument type: [in|out|inout]') + warnings += 1 + + return warnings + + def Depart(self, node, warnings, childdata): + __pychecker__ = 'unusednames=node' + for child in childdata: + warnings += child + return warnings + +def Lint(ast): + if GetOption('wcomment'): ast.SetProperty('wcomment', True) + if GetOption('wenum'): ast.SetProperty('wenum', True) + if GetOption('winline'): ast.SetProperty('winilne', True) + if GetOption('wparam'): ast.SetProperty('wparam', True) + if GetOption('wpass'): ast.SetProperty('wpass', True) + + skipList = [] + for filenode in ast.GetListOf('File'): + name = filenode.GetProperty('NAME') + if filenode.GetProperty('ERRORS') > 0: + ErrOut.Log('%s : Skipped due to errors.', name) + skipList.append(filenode) + continue + warnings = IDLLinter().Visit(filenode, 0) + if warnings: + WarnOut.Log('%s warning(s) for %s\n' % (warnings, name)) + return skipList diff --git a/ppapi/generators/idl_parser.py b/ppapi/generators/idl_parser.py index 77093f6..30e487b 100644 --- a/ppapi/generators/idl_parser.py +++ b/ppapi/generators/idl_parser.py @@ -35,6 +35,7 @@ from idl_log import ErrOut, InfoOut, WarnOut from idl_lexer import IDLLexer from idl_node import IDLAttribute, IDLFile, IDLNode from idl_option import GetOption, Option, ParseOptions +from idl_lint import Lint from ply import lex from ply import yacc @@ -44,8 +45,6 @@ Option('parse_debug', 'Debug parse reduction steps.') Option('token_debug', 'Debug token generation.') Option('dump_tree', 'Dump the tree.') Option('srcroot', 'Working directory.', default='../api') -Option('wcomment', 'Disable warning for missing comment.') -Option('wenum', 'Disable warning for missing enum value.') # # ERROR_REMAP @@ -710,26 +709,6 @@ class IDLParser(IDLLexer): return tok # -# VerifyProduction -# -# Once the node is built, we will check for certain types of issues -# - def VerifyProduction(self, node): - comment = node.GetOneOf('Comment') - if node.cls in ['Interface', 'Struct', 'Member'] and not comment: - if not GetOption('wcomment') and not node.GetProperty('wcomment'): - self.Warn(node, 'Missing comment for %s.' % node) - elif node.cls in ['EnumItem'] and not node.GetProperty('VALUE'): - if not GetOption('wenum'): - self.Warn(node, 'Missing value for enumeration %s.' % node) - elif node.cls in ['Param']: - found = False; - for form in ['in', 'inout', 'out']: - if node.GetProperty(form): found = True - if not found: self.Warn(node, 'Missing argument type: [in|out|inout]') - - -# # BuildProduction # # Production is the set of items sent to a grammar rule resulting in a new @@ -747,7 +726,6 @@ class IDLParser(IDLLexer): out = IDLNode(cls, filename, lineno, pos, childlist) if self.build_debug: InfoOut.Log("Building %s" % out) - self.VerifyProduction(out) return out def BuildNamed(self, cls, p, index, childlist=None): @@ -1010,6 +988,8 @@ def ParseFiles(filenames): ast = IDLAst(filenodes) if GetOption('dump_tree'): ast.Dump(0) + + Lint(ast) return ast diff --git a/ppapi/generators/idl_visitor.py b/ppapi/generators/idl_visitor.py index 40a8579..3824141 100644 --- a/ppapi/generators/idl_visitor.py +++ b/ppapi/generators/idl_visitor.py @@ -10,11 +10,13 @@ # IDLVisitor # # The IDLVisitor class will traverse an AST truncating portions of the tree -# that fail due to class or version filters. For each node, after the filter -# passes, the visitor will call the 'Arive' member passing in the node and -# and data passing in from the parent call. It will then Visit the children. -# When done processing children, the visitor will call the 'Depart' member -# before returning +# when 'VisitFilter' returns false. After the filter returns true, for each +# node, the visitor will call the 'Arrive' member passing in the node and +# and generic data object from the parent call. The returned value is then +# passed to all children who's results are aggregated into a list. The child +# results along with the original Arrive result are passed to the Depart +# function which returns the final result of the Visit. By default this is +# the exact value that was return from the original arrive. # class IDLVisitor(object): @@ -45,9 +47,11 @@ class IDLVisitor(object): return out def Arrive(self, node, data): + __pychecker__ = 'unusednames=node' return data def Depart(self, node, data, childdata): + __pychecker__ = 'unusednames=node,childdata' return data |