From patchwork Sun Apr 1 15:06:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Conole X-Patchwork-Id: 894020 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Ddxv57twz9s15 for ; Mon, 2 Apr 2018 01:07:31 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id D4717E83; Sun, 1 Apr 2018 15:07:01 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 2A1E7E4E for ; Sun, 1 Apr 2018 15:07:00 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 64B78628 for ; Sun, 1 Apr 2018 15:06:59 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9CA978182D0C; Sun, 1 Apr 2018 15:06:58 +0000 (UTC) Received: from dhcp-25.97.bos.redhat.com (ovpn-120-201.rdu2.redhat.com [10.10.120.201]) by smtp.corp.redhat.com (Postfix) with ESMTP id 47B50215CDAF; Sun, 1 Apr 2018 15:06:58 +0000 (UTC) From: Aaron Conole To: dev@openvswitch.org Date: Sun, 1 Apr 2018 11:06:54 -0400 Message-Id: <20180401150654.5941-4-aconole@redhat.com> In-Reply-To: <20180401150654.5941-1-aconole@redhat.com> References: <20180401150654.5941-1-aconole@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Sun, 01 Apr 2018 15:06:58 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Sun, 01 Apr 2018 15:06:58 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'aconole@redhat.com' RCPT:'' X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 3/3] checkpatch: add a comment spell-checker X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Grow a new opt-in feature to check comments for possible spelling mistakes. Uses the 'enchant' library to provide a default link to aspell/ispell as the backend. Additionally, a custom set of kewords is included inline to match what would be possibly encountered in 'the wild'. The list is fairly comprehensive at this point. Signed-off-by: Aaron Conole --- utilities/checkpatch.py | 108 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py index 5ed85ac15..d7cf9976a 100755 --- a/utilities/checkpatch.py +++ b/utilities/checkpatch.py @@ -21,12 +21,66 @@ import os import re import sys +try: + import enchant + + extra_keywords = ['ovs', 'vswitch', 'vswitchd', 'ovs-vswitchd', 'netdev', + 'selinux', 'ovs-ctl', 'dpctl', 'ofctl', 'openvswitch', + 'dpdk', 'hugepage', 'hugepages', 'pmd', 'upcall', + 'vhost', 'rx', 'tx', 'vhostuser', 'openflow', 'qsort', + 'rxq', 'txq', 'perf', 'stats', 'struct', 'int', + 'char', 'bool', 'upcalls', 'nicira', 'bitmask', 'ipv4', + 'ipv6', 'tcp', 'tcp4', 'tcpv4', 'udp', 'udp4', 'udpv4', + 'icmp', 'icmp4', 'icmpv6', 'vlan', 'vxlan', 'cksum', + 'csum', 'checksum', 'ofproto', 'numa', 'mempool', + 'mempools', 'mbuf', 'mbufs', 'hmap', 'cmap', 'smap', + 'dhcpv4', 'dhcp', 'dhcpv6', 'opts', 'metadata', + 'geneve', 'mutex', 'netdev', 'netdevs', 'subtable', + 'virtio', 'qos', 'policer', 'datapath', 'tunctl', + 'attr', 'ethernet', 'ether', 'defrag', 'defragment', + 'loopback', 'sflow', 'acl', 'initializer', 'recirc', + 'xlated', 'unclosed', 'netlink', 'msec', 'usec', + 'nsec', 'ms', 'us', 'ns', 'kilobits', 'kbps', + 'kilobytes', 'megabytes', 'mbps', 'gigabytes', 'gbps', + 'megabits', 'gigabits', 'pkts', 'tuple', 'miniflow', + 'megaflow', 'conntrack', 'vlans', 'vxlans', 'arg', + 'tpid', 'xbundle', 'xbundles', 'mbundle', 'mbundles', + 'netflow', 'localnet', 'odp', 'pre', 'dst', 'dest', + 'src', 'ethertype', 'cvlan', 'ips', 'msg', 'msgs', + 'liveness', 'userspace', 'eventmask', 'datapaths', + 'slowpath', 'fastpath', 'multicast', 'unicast', + 'revalidation', 'namespace', 'qdisc', 'uuid', 'ofport', + 'subnet', 'revalidation', 'revalidator', 'revalidate', + 'l2', 'l3', 'l4', 'openssl', 'mtu', 'ifindex', 'enum', + 'enums', 'http', 'https', 'num', 'vconn', 'vconns', + 'conn', 'nat', 'memset', 'memcmp', 'strcmp', + 'strcasecmp', 'tc', 'ufid', 'api', 'ofpbuf', 'ofpbufs', + 'hashmaps', 'hashmap', 'deref', 'dereference', 'hw', + 'prio', 'sendmmsg', 'sendmsg', 'malloc', 'free', 'alloc', + 'pid', 'ppid', 'pgid', 'uid', 'gid', 'sid', 'utime', + 'stime', 'cutime', 'cstime', 'vsize', 'rss', 'rsslim', + 'whcan', 'gtime', 'eip', 'rip', 'cgtime', 'dbg', 'gw', + 'sbrec', 'bfd', 'sizeof', 'pmds', 'nic', 'nics', 'hwol', + 'encap', 'decap', 'tlv', 'tlvs', 'decapsulation', 'fd', + 'cacheline', 'xlate', 'skiplist', 'idl', 'comparator', + 'natting', 'alg', 'pasv', 'epasv', 'wildcard', 'nated', + 'amd64', 'x86_64', 'recirculation'] + + spell_check_dict = enchant.Dict("en_US") + for kw in extra_keywords: + spell_check_dict.add(kw) + + no_spellcheck = False +except: + no_spellcheck = True + __errors = 0 __warnings = 0 print_file_name = None checking_file = False total_line = 0 colors = False +spellcheck_comments = False def get_color_end(): @@ -233,7 +287,7 @@ def has_xxx_mark(line): return __regex_has_xxx_mark.match(line) is not None -def filter_comments(current_line): +def filter_comments(current_line, keep=False): """remove all of the c-style comments in a line""" STATE_NORMAL = 0 STATE_COMMENT_SLASH = 1 @@ -245,6 +299,9 @@ def filter_comments(current_line): check_state = STATE_NORMAL only_whitespace = True + if keep: + check_state = STATE_COMMENT_CONTENTS + for c in current_line: if c == '/': if state == STATE_NORMAL: @@ -287,6 +344,38 @@ def filter_comments(current_line): return sanitized_line +def check_comment_spelling(line): + if no_spellcheck or not spellcheck_comments: + return False + + comment_words = filter_comments(line, True).replace(':', ' ').split(' ') + for word in comment_words: + skip = False + strword = re.subn(r'\W+', '', word)[0].replace(',', '') + if len(strword) and not spell_check_dict.check(strword.lower()): + if any([check_char in word + for check_char in ['=', '(', '-', '_', '/', '\'']]): + skip = True + + # special case the '.' + if '.' in word and not word.endswith('.'): + skip = True + + # skip proper nouns and references to macros + if strword.isupper() or (strword[0].isupper() and + strword[1:].islower()): + skip = True + + # skip words that start with numbers + if strword.startswith(tuple('0123456789')): + skip = True + + if not skip: + return True + + return False + + checks = [ {'regex': None, 'match_name': @@ -330,6 +419,11 @@ checks = [ 'prereq': lambda x: has_comment(x), 'check': lambda x: has_xxx_mark(x), 'print': lambda: print_warning("Comment with 'xxx' marker")}, + + {'regex': '(\.c|\.h)(\.in)?$', 'match_name': None, + 'prereq': lambda x: has_comment(x), + 'check': lambda x: check_comment_spelling(x), + 'print': lambda: print_warning("Check for spelling mistakes")}, ] @@ -535,6 +629,7 @@ Check options: -b|--skip-block-whitespace Skips the if/while/for whitespace tests -l|--skip-leading-whitespace Skips the leading whitespace test -s|--skip-signoff-lines Tolerate missing Signed-off-by line +-S|--spellcheck-comments Check C comments for possible spelling mistakes -t|--skip-trailing-whitespace Skips the trailing whitespace test""" % sys.argv[0]) @@ -582,13 +677,14 @@ if __name__ == '__main__': sys.argv[1:]) n_patches = int(numeric_options[-1][1:]) if numeric_options else 0 - optlist, args = getopt.getopt(args, 'bhlstf', + optlist, args = getopt.getopt(args, 'bhlstfS', ["check-file", "help", "skip-block-whitespace", "skip-leading-whitespace", "skip-signoff-lines", - "skip-trailing-whitespace"]) + "skip-trailing-whitespace", + "spellcheck-comments"]) except: print("Unknown option encountered. Please rerun with -h for help.") sys.exit(-1) @@ -607,6 +703,12 @@ if __name__ == '__main__': skip_trailing_whitespace_check = True elif o in ("-f", "--check-file"): checking_file = True + elif o in ("-S", "--spellcheck-comments"): + if no_spellcheck: + print("WARNING: The enchant library isn't availble.") + print(" Please install python enchant.") + else: + spellcheck_comments = True else: print("Unknown option '%s'" % o) sys.exit(-1)