summaryrefslogtreecommitdiffstats
path: root/ppapi/generators
diff options
context:
space:
mode:
authornoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-22 16:34:13 +0000
committernoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-22 16:34:13 +0000
commitcaff0c340f4abbe36fb5ad24f2c55811003bea8d (patch)
treeca34d1223453509e12183a9f50a1862d0ca127e0 /ppapi/generators
parent05d7cf8c9bbf1585224fe839184fbc5d9f9b70dd (diff)
downloadchromium_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.py120
-rw-r--r--ppapi/generators/idl_parser.py26
-rw-r--r--ppapi/generators/idl_visitor.py14
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