summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2014-11-17 12:55:58 (GMT)
committerSwift Review <review@swift.im>2014-12-10 13:47:44 (GMT)
commit08c90f11b20dc8413a3fb27a9334ff3f0466b116 (patch)
tree7190765f29290fe8cf114bf5a692636f5c974bd2 /BuildTools
parent59cf59db314becf523fea2b840d7a237c2f6f246 (diff)
downloadswift-08c90f11b20dc8413a3fb27a9334ff3f0466b116.zip
swift-08c90f11b20dc8413a3fb27a9334ff3f0466b116.tar.bz2
Add FixIncludes.py utility.
This tool reads in implementation or header files and groups and sorts include statements at the top according to our guidelines. It does not support files using #if statements in head of the file. Change-Id: I34b02546ecaf1653372f6edd319126b2ebb22ab5
Diffstat (limited to 'BuildTools')
-rw-r--r--BuildTools/FixIncludes.py134
1 files changed, 134 insertions, 0 deletions
diff --git a/BuildTools/FixIncludes.py b/BuildTools/FixIncludes.py
new file mode 100644
index 0000000..def2dd5
--- /dev/null
+++ b/BuildTools/FixIncludes.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+
+import sys;
+import os;
+import re;
+from sets import Set
+
+filename = sys.argv[1]
+
+filename_base = os.path.basename(filename)
+(filename_name, filename_ext) = os.path.splitext(filename_base)
+
+c_stdlib_headers = Set(["assert.h", "limits.h", "signal.h", "stdlib.h", "ctype.h", "locale.h", "stdarg.h", "string.h", "errno.h", "math.h", "stddef.h", "time.h", "float.h", "setjmp.h", "stdio.h", "iso646.h", "wchar.h", "wctype.h", "complex.h", "inttypes.h", "stdint.h", "tgmath.h", "fenv.h", "stdbool.h"])
+
+cpp_stdlib_headers = Set(["algorithm", "fstream", "list", "regex", "typeindex", "array", "functional", "locale", "set", "typeinfo", "atomic", "future", "map", "sstream", "type_traits", "bitset", "initializer_list", "memory", "stack", "unordered_map", "chrono", "iomanip", "mutex", "stdexcept", "unordered_set", "codecvt", "ios", "new", "streambuf", "utility", "complex", "iosfwd", "numeric", "string", "valarray", "condition_variable", "iostream", "ostream", "strstream", "vector", "deque", "istream", "queue", "system_error", "exception", "iterator", "random", "thread", "forward_list", "limits", "ratio", "tuple", "cassert", "ciso646", "csetjmp", "cstdio", "ctime", "cctype", "climits", "csignal", "cstdlib", "cwchar", "cerrno", "clocale", "cstdarg", "cstring", "cwctype", "cfloat", "cmath", "cstddef"])
+
+class HeaderType:
+ PRAGMA_ONCE, CORRESPONDING_HEADER, C_STDLIB, CPP_STDLIB, BOOST, QT, OTHER, SWIFTEN, SWIFT_CONTROLLERS, SWIFTOOLS, SWIFT = range(11)
+
+def findHeaderBlock(lines):
+ start = False
+ end = False
+
+ for idx, line in enumerate(lines):
+ if not start and line.startswith("#"):
+ start = idx
+ elif start and (not end) and (not line.startswith("#")) and line.strip():
+ end = idx-1
+ break
+ return (start, end)
+
+def lineToFileName(line):
+ match = re.match( r'#include "(.*)"', line)
+ if match:
+ return match.group(1)
+ match = re.match( r'#include <(.*)>', line)
+ if match:
+ return match.group(1)
+ return False
+
+def fileNameToHeaderType(name):
+ if name.endswith(filename_name + ".h"):
+ return HeaderType.CORRESPONDING_HEADER
+
+ if name in c_stdlib_headers:
+ return HeaderType.C_STDLIB
+
+ if name in cpp_stdlib_headers:
+ return HeaderType.CPP_STDLIB
+
+ if name.startswith("boost"):
+ return HeaderType.BOOST
+
+ if name.startswith("Q"):
+ return HeaderType.QT
+
+ if name.startswith("Swiften"):
+ return HeaderType.SWIFTEN
+
+ if name.startswith("Swift/Controllers"):
+ return HeaderType.SWIFT_CONTROLLERS
+
+ if name.startswith("SwifTools"):
+ return HeaderType.SWIFTOOLS
+
+ if name.startswith("Swift"):
+ return HeaderType.SWIFT
+
+ return HeaderType.OTHER
+
+def serializeHeaderGroups(groups):
+ headerList = []
+ for group in range(0, HeaderType.SWIFT + 1):
+ if group in groups:
+ headers = sorted(groups[group])
+ headerList.extend(headers)
+ headerList.extend(["\n"])
+ headerList.pop()
+ return headerList
+
+def cleanHeaderFile(content, headerStart, headerEnd, headerGroups):
+ del content[headerStart:headerEnd]
+ newHeaders = serializeHeaderGroups(headerGroups)
+ content[headerStart:1] = newHeaders
+
+ for line in content:
+ print line,
+
+def cleanImplementationFile(content, headerStart, headerEnd, headerGroups):
+ del content[headerStart:headerEnd]
+ newHeaders = serializeHeaderGroups(headerGroups)
+ content[headerStart:1] = newHeaders
+
+ for line in content:
+ print line,
+
+
+containsIf = False
+
+with open(filename) as f:
+ content = f.readlines()
+
+(headerStart, headerEnd) = findHeaderBlock(content)
+
+headerGroups = {}
+
+for line in content[headerStart:headerEnd]:
+ if line.strip():
+ if line.strip().startswith("#if "):
+ containsIf = True
+ break
+
+ if line.strip().startswith("#pragma once"):
+ headerType = HeaderType.PRAGMA_ONCE
+ else:
+ headerType = fileNameToHeaderType(lineToFileName(line))
+
+ filename = lineToFileName(line)
+ if headerType in headerGroups:
+ headerGroups[headerType].append(line)
+ else:
+ headerGroups[headerType] = [line]
+
+if containsIf:
+ print "Cannot format headers containing preprocessor if statements"
+ exit(1)
+
+if filename_base.endswith(".h"):
+ if not HeaderType.PRAGMA_ONCE in headerGroups:
+ print "Missing #pragma once!"
+ exit(2)
+ cleanHeaderFile(content, headerStart, headerEnd, headerGroups)
+elif filename_base.endswith(".cpp"):
+ cleanImplementationFile(content, headerStart, headerEnd, headerGroups)