15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" Lint for IDL """
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_log import ErrOut, InfoOut, WarnOut
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_node import IDLAttribute, IDLNode
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_ast import IDLAst
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_option import GetOption, Option, ParseOptions
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_outfile import IDLOutFile
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_visitor import IDLVisitor
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('wcomment', 'Disable warning for missing comment.')
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('wenum', 'Disable warning for missing enum value.')
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('winline', 'Disable warning for inline blocks.')
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('wname', 'Disable warning for inconsistent interface name.')
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('wnone', 'Disable all warnings.')
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('wparam', 'Disable warning for missing [in|out|inout] on param.')
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('wpass', 'Disable warning for mixed passByValue and returnByValue.')
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IDLLinter
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Once the AST is build, we need to resolve the namespace and version
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# information.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IDLLinter(IDLVisitor):
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def VisitFilter(self, node, data):
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __pychecker__ = 'unusednames=node,data'
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return not node.IsA('Comment', 'Copyright')
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Arrive(self, node, errors):
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __pychecker__ = 'unusednames=node,errors'
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    warnings = 0
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Interface', 'Member', 'Struct', 'Enum', 'EnumItem', 'Typedef'):
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      comments = node.GetListOf('Comment')
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not comments and not node.GetProperty('wcomment'):
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node.Warning('Expecting a comment.')
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        warnings += 1
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('File'):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      labels = node.GetListOf('Label')
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      interfaces = node.GetListOf('Interface')
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if interfaces and not labels:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node.Warning('Expecting a label in a file containing interfaces.')
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Struct', 'Typedef') and not node.GetProperty('wpass'):
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.GetProperty('passByValue'):
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pbv = 'is'
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pbv = 'is not'
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.GetProperty('returnByValue'):
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret = 'is'
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret = 'is not'
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if pbv != ret:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node.Warning('%s passByValue but %s returnByValue.' % (pbv, ret))
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        warnings += 1
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('EnumItem'):
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not node.GetProperty('VALUE') and not node.GetProperty('wenum'):
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node.Warning('Expecting value for enumeration.')
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        warnings += 1
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Interface'):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      macro = node.GetProperty('macro')
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if macro and not node.GetProperty('wname'):
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node.Warning('Interface name inconsistent: %s' % macro)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        warnings += 1
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Inline') and not node.GetProperty('winline'):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inline_type = node.GetProperty('NAME')
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node.parent.Warning('Requires an inline %s block.' % inline_type)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      warnings += 1
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Callspec') and not node.GetProperty('wparam'):
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out = False
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for arg in node.GetListOf('Param'):
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if arg.GetProperty('out'):
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          out = True
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if arg.GetProperty('in') and out:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          arg.Warning('[in] parameter after [out] parameter')
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          warnings += 1
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Param') and not node.GetProperty('wparam'):
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      found = False;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for form in ['in', 'inout', 'out']:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if node.GetProperty(form): found = True
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not found:
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node.Warning('Missing argument type: [in|out|inout]')
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        warnings += 1
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return warnings
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Depart(self, node, warnings, childdata):
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __pychecker__ = 'unusednames=node'
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for child in childdata:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      warnings += child
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return warnings
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Lint(ast):
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options = ['wcomment', 'wenum', 'winline', 'wparam', 'wpass', 'wname']
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wnone = GetOption('wnone')
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for opt in options:
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if wnone or GetOption(opt): ast.SetProperty(opt, True)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  skipList = []
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for filenode in ast.GetListOf('File'):
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name = filenode.GetProperty('NAME')
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if filenode.GetProperty('ERRORS') > 0:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ErrOut.Log('%s : Skipped due to errors.' % name)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skipList.append(filenode)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    warnings = IDLLinter().Visit(filenode, 0)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if warnings:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WarnOut.Log('%s warning(s) for %s\n' % (warnings, name))
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return skipList
123