xref: /haiku/src/tools/checkstyle/checkstyle.py (revision 9e25244c5e9051f6cd333820d6332397361abd6c)
1#!/usr/bin/env python
2#
3# Copyright 2009, Alexandre Deckner, alex@zappotek.com
4# Distributed under the terms of the MIT License.
5#
6import re, sys, os
7from utils import *
8
9
10def processMatches(matches, name, text, highlights):
11    for match in matches:
12        printMatch(name, match, text)
13        highlights.append((match.start(), match.end(), name))
14
15
16def run(fileSet, rules, outputFileName):
17    openHtml(fileSet, outputFileName)
18
19    for fileName in fileSet:
20        print "\nChecking " + fileName + ":"
21        file = open(fileName, 'r')
22        text = file.read()
23
24        highlights = []
25
26        for name, regexp in rules.items():
27            processMatches(regexp.finditer(text), name, text, highlights)
28
29        highlights.sort()
30        highlights = checkHighlights(highlights)
31
32        file.close()
33
34        renderHtml(text, highlights, fileName, outputFileName)
35
36    closeHtml(outputFileName)
37
38
39def visit(result, dir, names):
40    extensions = [".cpp", ".h"]
41    vcsCacheDirectory = [".bzr", ".git", ".hg", ".svn"]
42
43    for name in reversed(names):
44        for vcd in vcsCacheDirectory:
45            if name == vcd:
46                print(vcd + " cache directory has been ignored")
47                names.remove(vcd)
48
49    for name in names:
50        path = os.path.join(dir, name)
51        if os.path.isfile(path) and os.path.splitext(name)[1] in extensions:
52            print "adding", path
53            result.append(path)
54
55
56cppRules = {}
57cppRules["Line over 100 char"] = re.compile('[^\n]{101,}')
58cppRules["Spaces instead of tabs"] = re.compile('   ')
59cppRules["Missing space after control statement"] \
60    = re.compile('(for|if|while|switch)\(')
61cppRules["Missing space at comment start"] = re.compile('//\w')
62cppRules["Missing space after operator"] \
63    = re.compile('\w(==|[,=>/+\-*;\|])\w')
64cppRules["Operator at line end"] = re.compile('([*=/+\-\|\&\?]|\&&|\|\|)(?=\n)')
65cppRules["Missing space"] = re.compile('\){')
66cppRules["Mixed tabs/spaces"] = re.compile('( \t]|\t )+')
67cppRules["Malformed else"] = re.compile('}[ \t]*\n[ \t]*else')
68cppRules["Lines between functions > 2"] \
69    = re.compile('(?<=\n})([ \t]*\n){3,}(?=\n)')
70cppRules["Lines between functions &lt; 2"] \
71    = re.compile('(?<=\n})([ \t]*\n){0,2}(?=.)')
72cppRules["Windows Line Ending"] = re.compile('\r')
73cppRules["Bad pointer/reference style"] \
74    = re.compile('(?<=\w) [*&](?=(\w|[,\)]))')
75
76# TODO: ignore some rules in comments
77#cppRules["-Comment 1"] = re.compile('[^/]/\*(.|[\r\n])*?\*/')
78#cppRules["-Comment 2"] = re.compile('(//)[^\n]*')
79
80
81if len(sys.argv) >= 2 and sys.argv[1] != "--help":
82    files = []
83    for arg in sys.argv[1:]:
84        if os.path.isfile(arg):
85            files.append(arg)
86        else:
87            os.path.walk(arg, visit, files)
88    run(files, cppRules, "styleviolations.html")
89else:
90    print "Usage: python checkstyle.py file.cpp [file2.cpp] [directory]\n"
91    print "Checks c++ source files against the Haiku Coding Guidelines."
92    print "Outputs an html report in the styleviolations.html file.\n"
93