Prefer clang-format for sorting #import/#include

This should have no direct user impact.

We currently have two ways of sorting `#import` and `#include`
statements:

1. With our precommit script
2. With `clang-format` (via `git-clang-format`)

It *looks* like we aren't using `clang-format` (because of the
`SortIncludes: false` option in `.clang-format`) but we are,
which you can see by running `clang-format --dump-config`. As a separate
issue, it seems like we're not picking up the `clang-format`
configuration file (`clang-format --style=file:.clang-format
--dump-config` gives different results).

I've run into situations where the two of them "fight", so I think the
best thing to do is pick one. After some discussion, we decided to pick
`clang-format`.
This commit is contained in:
Evan Hahn
2022-08-04 16:25:08 -05:00
committed by Evan Hahn
parent 0f232ce25b
commit f8afc58b42
2 changed files with 1 additions and 172 deletions

View File

@@ -13,5 +13,5 @@ PointerBindsToType: false
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
TabWidth: 8 TabWidth: 8
UseTab: Never UseTab: Never
SortIncludes: false SortIncludes: CaseSensitive
... ...

View File

@@ -17,153 +17,6 @@ git_repo_path = os.path.abspath(
) )
class include:
def __init__(self, isInclude, isQuote, body, comment):
self.isInclude = isInclude
self.isQuote = isQuote
self.body = body
self.comment = comment
def format(self):
result = "%s %s%s%s" % (
("#include" if self.isInclude else "#import"),
('"' if self.isQuote else "<"),
self.body.strip(),
('"' if self.isQuote else ">"),
)
if self.comment.strip():
result += " " + self.comment.strip()
return result
def is_include_or_import(line):
line = line.strip()
if line.startswith("#include "):
return True
elif line.startswith("#import "):
return True
else:
return False
def parse_include(line):
remainder = line.strip()
if remainder.startswith("#include "):
isInclude = True
remainder = remainder[len("#include ") :]
elif remainder.startswith("#import "):
isInclude = False
remainder = remainder[len("#import ") :]
elif remainder == "//":
return None
elif not remainder:
return None
else:
print("Unexpected import or include: " + line)
sys.exit(1)
comment = None
if remainder.startswith('"'):
isQuote = True
endIndex = remainder.find('"', 1)
if endIndex < 0:
print("Unexpected import or include: " + line)
sys.exit(1)
body = remainder[1:endIndex]
comment = remainder[endIndex + 1 :]
elif remainder.startswith("<"):
isQuote = False
endIndex = remainder.find(">", 1)
if endIndex < 0:
print("Unexpected import or include: " + line)
sys.exit(1)
body = remainder[1:endIndex]
comment = remainder[endIndex + 1 :]
else:
print("Unexpected import or include: " + remainder)
sys.exit(1)
return include(isInclude, isQuote, body, comment)
def parse_includes(text):
lines = text.split("\n")
includes = []
for line in lines:
include = parse_include(line)
if include:
includes.append(include)
return includes
def sort_include_block(text, filepath, filename, file_extension):
includes = parse_includes(text)
blocks = []
file_extension = file_extension.lower()
for include in includes:
include.isInclude = False
if file_extension in ("c", "cpp", "hpp"):
for include in includes:
include.isInclude = True
elif file_extension in ("m"):
for include in includes:
include.isInclude = False
# Make sure matching header is first.
matching_header_includes = []
other_includes = []
def is_matching_header(include):
filename_wo_ext = os.path.splitext(filename)[0]
include_filename_wo_ext = os.path.splitext(os.path.basename(include.body))[0]
return filename_wo_ext == include_filename_wo_ext
for include in includes:
if is_matching_header(include):
matching_header_includes.append(include)
else:
other_includes.append(include)
includes = other_includes
def formatBlock(includes):
lines = set([include.format() for include in includes])
return "\n".join(sorted(lines))
includeAngles = [
include for include in includes if include.isInclude and not include.isQuote
]
includeQuotes = [
include for include in includes if include.isInclude and include.isQuote
]
importAngles = [
include
for include in includes
if (not include.isInclude) and not include.isQuote
]
importQuotes = [
include for include in includes if (not include.isInclude) and include.isQuote
]
if matching_header_includes:
blocks.append(formatBlock(matching_header_includes))
if includeQuotes:
blocks.append(formatBlock(includeQuotes))
if includeAngles:
blocks.append(formatBlock(includeAngles))
if importQuotes:
blocks.append(formatBlock(importQuotes))
if importAngles:
blocks.append(formatBlock(importAngles))
return "\n".join(blocks) + "\n"
def sort_forward_decl_statement_block(text, filepath, filename, file_extension): def sort_forward_decl_statement_block(text, filepath, filename, file_extension):
lines = text.split("\n") lines = text.split("\n")
lines = [line.strip() for line in lines if line.strip()] lines = [line.strip() for line in lines if line.strip()]
@@ -289,29 +142,6 @@ def find_forward_protocol_statement_section(text):
return find_matching_section(text, is_forward_protocol_statement) return find_matching_section(text, is_forward_protocol_statement)
def find_include_section(text):
def is_include_line(line):
return is_include_or_import(line)
# return is_include_or_import_or_empty(line)
return find_matching_section(text, is_include_line)
def sort_includes(filepath, filename, file_extension, text):
# print 'sort_includes', filepath
if file_extension not in (".h", ".m", ".mm"):
return text
return sort_matching_blocks(
"sort_includes",
filepath,
filename,
file_extension,
text,
find_include_section,
sort_include_block,
)
def sort_forward_class_statements(filepath, filename, file_extension, text): def sort_forward_class_statements(filepath, filename, file_extension, text):
# print 'sort_class_statements', filepath # print 'sort_class_statements', filepath
if file_extension not in (".h", ".m", ".mm"): if file_extension not in (".h", ".m", ".mm"):
@@ -361,7 +191,6 @@ def process(filepath):
original_text = text original_text = text
text = sort_includes(filepath, filename, file_ext, text)
text = sort_forward_class_statements(filepath, filename, file_ext, text) text = sort_forward_class_statements(filepath, filename, file_ext, text)
text = sort_forward_protocol_statements(filepath, filename, file_ext, text) text = sort_forward_protocol_statements(filepath, filename, file_ext, text)