[prev in list] [next in list] [prev in thread] [next in thread] 

List:       haiku-commits
Subject:    [haiku-commits] r33856 - in haiku/trunk/src/tools: . checkstyle
From:       alex () zappotek ! com
Date:       2009-10-31 22:20:26
Message-ID: 20091031222026.2AFF3682BC () svn ! haiku-os ! org
[Download RAW message or body]

Author: aldeck
Date: 2009-10-31 23:20:25 +0100 (Sat, 31 Oct 2009)
New Revision: 33856
Changeset: http://dev.haiku-os.org/changeset/33856/haiku

Added:
   haiku/trunk/src/tools/checkstyle/
   haiku/trunk/src/tools/checkstyle/checkstyle.py
   haiku/trunk/src/tools/checkstyle/utils.py
Log:
* Style checker for the Haiku C++ coding guidelines
* Added an html report output with highlights and tooltips
* Still a few false positives and rules missing. Some regex could be reworked
* TODO: ignore some rules when in comments, multifile support



Added: haiku/trunk/src/tools/checkstyle/checkstyle.py
===================================================================
--- haiku/trunk/src/tools/checkstyle/checkstyle.py	                        (rev 0)
+++ haiku/trunk/src/tools/checkstyle/checkstyle.py	2009-10-31 22:20:25 UTC (rev 33856)
@@ -0,0 +1,55 @@
+#
+# Copyright 2009, Alexandre Deckner, alex@zappotek.com
+# Distributed under the terms of the MIT License.
+#
+import re, sys
+from utils import *
+
+
+def processMatches(matches, name, text, highlights):
+    for match in matches:
+        printMatch(name, match, text)
+        highlights.append((match.start(), match.end(), name))
+
+
+def run(sourceFile, rules):
+    file = open(sourceFile, 'r')
+    text = file.read()
+
+    highlights = []
+
+    for name, regexp in rules.items():
+        processMatches(regexp.finditer(text), name, text, highlights)
+
+    highlights.sort()
+    highlights = checkHighlights(highlights)
+
+    file.close()
+    renderHtml(text, highlights, sourceFile, "styleviolations.html")
+
+
+cppRules = {}
+cppRules["Line over 80 char"] = re.compile('[^\n]{81,}')
+cppRules["Spaces instead of tabs"] = re.compile('   ')
+cppRules["Missing space after for/if/select/while"] = re.compile('(for|if|select|while)\(')
+cppRules["Missing space at comment start"] = re.compile('//[a-zA-Z0-9]')
+cppRules["Missing space after operator"] \
+    = re.compile('[a-zA-Z0-9](==|[,=>/+\-*;\|])[a-zA-Z0-9]')
+cppRules["Operator at line end"] = re.compile('([*=/+\-\|\&\?]|\&&|\|\|)\n')
+cppRules["Missing space"] = re.compile('\){')
+cppRules["Mixed tabs/spaces"] = re.compile('( \t]|\t )+')
+cppRules["Malformed else"] = re.compile('}[ \t]*\n[ \t]*else')
+cppRules["Lines between functions > 2"] = re.compile('\n}([ \t]*\n){4,}')
+cppRules["Lines between functions < 2"] = re.compile('\n}([ \t]*\n){0,2}.')
+
+# TODO: ignore some rules in comments
+#cppRules["-Comment 1"] = re.compile('[^/]/\*(.|[\r\n])*?\*/')
+#cppRules["-Comment 2"] = re.compile('(//)[^\n]*')
+
+
+if len(sys.argv) == 2 and sys.argv[1] != "--help":
+    run(sys.argv[1], cppRules)
+else:
+	print "Usage: python checkstyle.py file.cpp\n"
+	print "Checks a c++ source file against the Haiku Coding Guidelines."
+	print "Outputs an highlighted html report in the styleviolations.html file.\n"

Added: haiku/trunk/src/tools/checkstyle/utils.py
===================================================================
--- haiku/trunk/src/tools/checkstyle/utils.py	                        (rev 0)
+++ haiku/trunk/src/tools/checkstyle/utils.py	2009-10-31 22:20:25 UTC (rev 33856)
@@ -0,0 +1,165 @@
+#
+# Copyright 2009, Alexandre Deckner, alex@zappotek.com
+# Distributed under the terms of the MIT License.
+#
+from cgi import escape
+
+
+# prints match to stdout
+def printMatch(name, match, source):
+    start = match.start()
+    end = match.end()
+    startLine = source.count('\n', 0, start)
+    startColumn = start - source.rfind('\n', 0, start)
+    print name + " (line " + str(startLine + 1) + ", " + str(startColumn) \
+        + "): '" + match.group().replace('\n','\\n') + "'"
+
+
+# render in html, the file style.css is embedded
+def renderHtml(text, highlights, sourceFileName, outputFileName):
+    splittedText = highlightSplit(text, highlights)
+
+    #styleFile = open("style.css")
+    #style = styleFile.read()
+    #styleFile.close()
+
+    file = open(outputFileName, 'w')
+    file.write("""
+    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+    <head>
+        <title>Style violations in """ + sourceFileName.split('/')[-1] \
+         + """</title>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+        <style type="text/css">""" + cssStyle() + """</style>
+    </head>
+    <body>
+        <p>""" + sourceFileName + """</p>
+        <pre class="code">""")
+
+    temp = ""
+    count = 0
+    for slice in splittedText:
+        if count % 2 == 0:
+            temp += escape(slice) + '<highlight class="tooltip">'
+        else:
+            temp += escape(slice) + "<em>" + highlights[(count - 1) / 2][2] \
+                + "</em></highlight>"
+        count += 1
+
+    temp += "</highlight>" # close the superfluous last highlight
+
+    count = 1
+    for line in temp.split('\n'):
+        file.write(str(count).rjust(4) + ' |' + line + '<br>')
+        count += 1
+
+    file.write("""
+        </pre>
+    </body>
+    </html>""")
+
+    file.close()
+
+
+# highlight overlap check
+def highlightOverlaps(highlight1, highlight2):
+    #print "hl1", highlight1, "hl2", highlight2
+    return not(highlight2[0] > highlight1[1] or highlight1[0] > highlight2[1])
+
+
+# splits the string in three parts before, between and after the highlight
+def splitByHighlight(string, highlight):
+    return (string[:highlight[0]], string[highlight[0]:highlight[1]], \
+        string[highlight[1]:])
+
+
+# splits the source text on highlights boundaries so that we can escape to html
+# without the need to recalculate the highlights positions
+def highlightSplit(string, highlights):
+    splittedString = []
+    text = string
+    offset = 0
+    lastEnd = 0
+    for (start, end, name) in highlights:
+         if start >= lastEnd:
+            (before, between, after) = splitByHighlight( \
+                text, (start - offset, end - offset))
+            splittedString.append(before)
+            splittedString.append(between)
+            text = after
+            lastEnd = end
+            offset += len(before + between)
+         else:
+            print "overlap ", (start, end, name)
+    splittedString.append(text)
+    return splittedString
+
+
+# checkHighlights() checks for highlights overlaps
+def checkHighlights(highlights):
+    highlights.sort()
+
+    index = 0
+    lastHighlight = (-2, -1, '')
+
+    # merge overlapping highlights
+    for highlight in highlights:
+        if highlightOverlaps(highlight, lastHighlight):
+
+            newStart = min(lastHighlight[0], highlight[0])
+            newEnd = max(lastHighlight[1], highlight[1])
+            newComment = lastHighlight[2]
+
+            if (newComment.find(highlight[2]) == -1):
+                newComment += " + " + highlight[2]
+
+            highlight = (newStart, newEnd, newComment)
+            highlights[index] = highlight
+
+            # mark highlight to be deleted
+            highlights[index - 1] = (0, 0, "")
+
+        lastHighlight = highlight
+        index += 1
+
+    # remove "to be deleted" highlights
+    return [ (start, end, comment) for (start, end, comment) in highlights \
+        if (start, end, comment) != (0, 0, "") ]
+
+
+def cssStyle():
+	return """
+    highlight {
+        background: #ffff00;
+        color: #000000;
+    }
+
+    div.code pre {
+        font-family: monospace;
+    }
+
+    highlight.tooltip em {
+        display:none;
+    }
+
+    highlight.tooltip:hover {
+        border: 0;
+        position: relative;
+        z-index: 500;
+        text-decoration:none;
+    }
+
+    highlight.tooltip:hover em {
+        font-style: normal;
+        display: block;
+        position: absolute;
+        top: 20px;
+        left: -10px;
+        padding: 5px;
+        color: #000;
+        border: 1px solid #bbb;
+        background: #ffc;
+        width: auto;
+    }"""


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic