diff options
Diffstat (limited to 'ppapi/generators/idl_lint.py')
-rw-r--r-- | ppapi/generators/idl_lint.py | 120 |
1 files changed, 120 insertions, 0 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 |