idl_lint.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5""" Lint for IDL """
6
7import os
8import sys
9
10from idl_log import ErrOut, InfoOut, WarnOut
11from idl_node import IDLAttribute, IDLNode
12from idl_ast import IDLAst
13from idl_option import GetOption, Option, ParseOptions
14from idl_outfile import IDLOutFile
15from idl_visitor import IDLVisitor
16
17
18Option('wcomment', 'Disable warning for missing comment.')
19Option('wenum', 'Disable warning for missing enum value.')
20Option('winline', 'Disable warning for inline blocks.')
21Option('wname', 'Disable warning for inconsistent interface name.')
22Option('wnone', 'Disable all warnings.')
23Option('wparam', 'Disable warning for missing [in|out|inout] on param.')
24Option('wpass', 'Disable warning for mixed passByValue and returnByValue.')
25
26#
27# IDLLinter
28#
29# Once the AST is build, we need to resolve the namespace and version
30# information.
31#
32class IDLLinter(IDLVisitor):
33  def VisitFilter(self, node, data):
34    __pychecker__ = 'unusednames=node,data'
35    return not node.IsA('Comment', 'Copyright')
36
37  def Arrive(self, node, errors):
38    __pychecker__ = 'unusednames=node,errors'
39    warnings = 0
40    if node.IsA('Interface', 'Member', 'Struct', 'Enum', 'EnumItem', 'Typedef'):
41      comments = node.GetListOf('Comment')
42      if not comments and not node.GetProperty('wcomment'):
43        node.Warning('Expecting a comment.')
44        warnings += 1
45
46    if node.IsA('File'):
47      labels = node.GetListOf('Label')
48      interfaces = node.GetListOf('Interface')
49      if interfaces and not labels:
50        node.Warning('Expecting a label in a file containing interfaces.')
51
52    if node.IsA('Struct', 'Typedef') and not node.GetProperty('wpass'):
53      if node.GetProperty('passByValue'):
54        pbv = 'is'
55      else:
56        pbv = 'is not'
57      if node.GetProperty('returnByValue'):
58        ret = 'is'
59      else:
60        ret = 'is not'
61      if pbv != ret:
62        node.Warning('%s passByValue but %s returnByValue.' % (pbv, ret))
63        warnings += 1
64
65    if node.IsA('EnumItem'):
66      if not node.GetProperty('VALUE') and not node.GetProperty('wenum'):
67        node.Warning('Expecting value for enumeration.')
68        warnings += 1
69
70    if node.IsA('Interface'):
71      macro = node.GetProperty('macro')
72      if macro and not node.GetProperty('wname'):
73        node.Warning('Interface name inconsistent: %s' % macro)
74        warnings += 1
75
76    if node.IsA('Inline') and not node.GetProperty('winline'):
77      inline_type = node.GetProperty('NAME')
78      node.parent.Warning('Requires an inline %s block.' % inline_type)
79      warnings += 1
80
81    if node.IsA('Callspec') and not node.GetProperty('wparam'):
82      out = False
83      for arg in node.GetListOf('Param'):
84        if arg.GetProperty('out'):
85          out = True
86        if arg.GetProperty('in') and out:
87          arg.Warning('[in] parameter after [out] parameter')
88          warnings += 1
89
90    if node.IsA('Param') and not node.GetProperty('wparam'):
91      found = False;
92      for form in ['in', 'inout', 'out']:
93        if node.GetProperty(form): found = True
94      if not found:
95        node.Warning('Missing argument type: [in|out|inout]')
96        warnings += 1
97
98    return warnings
99
100  def Depart(self, node, warnings, childdata):
101    __pychecker__ = 'unusednames=node'
102    for child in childdata:
103      warnings += child
104    return warnings
105
106def Lint(ast):
107  options = ['wcomment', 'wenum', 'winline', 'wparam', 'wpass', 'wname']
108  wnone = GetOption('wnone')
109  for opt in options:
110    if wnone or GetOption(opt): ast.SetProperty(opt, True)
111
112  skipList = []
113  for filenode in ast.GetListOf('File'):
114    name = filenode.GetProperty('NAME')
115    if filenode.GetProperty('ERRORS') > 0:
116      ErrOut.Log('%s : Skipped due to errors.' % name)
117      skipList.append(filenode)
118      continue
119    warnings = IDLLinter().Visit(filenode, 0)
120    if warnings:
121      WarnOut.Log('%s warning(s) for %s\n' % (warnings, name))
122  return skipList
123