notepad-plus-plus/scintilla/scripts/HeaderCheck.py

117 lines
4.0 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
2019-05-04 18:14:48 +00:00
# Script to check that headers are in a consistent order
# Canonical header order is defined in a file, normally scripts/HeaderOrder.txt
# Requires Python 3.6 or later
2019-05-04 18:14:48 +00:00
import pathlib, sys
2019-05-04 18:14:48 +00:00
def IsHeader(x):
return x.strip().startswith("#") and \
("include" in x or "import" in x) and \
"dllimport" not in x
def HeaderFromIncludeLine(s):
#\s*#\s*(include|import)\s+\S+\s*
return s.strip()[1:].strip()[7:].strip()
2019-05-04 18:14:48 +00:00
def ExtractHeaders(file):
Update: Scintilla 5.3.5 Lexilla 5.2.5 update to Scinitlla Release 5.3.5 (https://www.scintilla.org/scintilla535.zip) Released 31 May 2023. On Win32, implement IME context sensitivity with IMR_DOCUMENTFEED. Feature #1310. On Win32 remove dependence on MSIMG32.DLL by replacing AlphaBlend by GdiAlphaBlend. Bug #1923. On Qt, stop movement of IME candidate box. On Qt, report correct caret position within paragraph for IME retrieve surrounding text. On Qt for Cocoa, fix crash in entry of multi-character strings with IME. and Lexilla Release 5.2.5 (https://www.scintilla.org/lexilla525.zip) Released 31 May 2023. Add CharacterSetArray constructor without setBase initial argument for common case where this is setNone and the initialSet argument completely defines the characters. This shortens and clarifies use of CharacterSetArray. Bash: implement highlighting inside quoted elements and here-docs. Controlled with properties lexer.bash.styling.inside.string, lexer.bash.styling.inside.backticks, lexer.bash.styling.inside.parameter, and lexer.bash.styling.inside.heredoc. Issue #154, Issue #153, Feature #1033. Bash: add property lexer.bash.command.substitution to choose how to style command substitutions. 0 → SCE_SH_BACKTICKS; 1 → surrounding "$(" and ")" as operators and contents styled as bash code; 2 → use distinct styles (base style + 64) for contents. Choice (2) is a provisional feature and details may change before it is finalized. Issue #153. Bash: fix nesting of parameters (SCE_SH_PARAM) like ${var/$sub/"${rep}}"}. Issue #154. Bash: fix single character special parameters like $? by limiting style. Issue #154. Bash: treat "$$" as special parameter and end scalars before "$". Issue #154. Bash: treat "<<" in arithmetic contexts as left bitwise shift operator instead of here-doc. Issue #137. Batch: style SCE_BAT_AFTER_LABEL used for rest of line after label which is not executed. Issue #148. F#: Lex interpolated verbatim strings as verbatim. Issue #156. VB: allow multiline strings when lexer.vb.strings.multiline set. Issue #151. Close #13729
2023-05-31 23:11:12 +00:00
with file.open(encoding="iso-8859-1") as infile:
return [HeaderFromIncludeLine(h) for h in infile if IsHeader(h)]
def ExtractWithPrefix(file, prefix):
Update: Scintilla 5.3.5 Lexilla 5.2.5 update to Scinitlla Release 5.3.5 (https://www.scintilla.org/scintilla535.zip) Released 31 May 2023. On Win32, implement IME context sensitivity with IMR_DOCUMENTFEED. Feature #1310. On Win32 remove dependence on MSIMG32.DLL by replacing AlphaBlend by GdiAlphaBlend. Bug #1923. On Qt, stop movement of IME candidate box. On Qt, report correct caret position within paragraph for IME retrieve surrounding text. On Qt for Cocoa, fix crash in entry of multi-character strings with IME. and Lexilla Release 5.2.5 (https://www.scintilla.org/lexilla525.zip) Released 31 May 2023. Add CharacterSetArray constructor without setBase initial argument for common case where this is setNone and the initialSet argument completely defines the characters. This shortens and clarifies use of CharacterSetArray. Bash: implement highlighting inside quoted elements and here-docs. Controlled with properties lexer.bash.styling.inside.string, lexer.bash.styling.inside.backticks, lexer.bash.styling.inside.parameter, and lexer.bash.styling.inside.heredoc. Issue #154, Issue #153, Feature #1033. Bash: add property lexer.bash.command.substitution to choose how to style command substitutions. 0 → SCE_SH_BACKTICKS; 1 → surrounding "$(" and ")" as operators and contents styled as bash code; 2 → use distinct styles (base style + 64) for contents. Choice (2) is a provisional feature and details may change before it is finalized. Issue #153. Bash: fix nesting of parameters (SCE_SH_PARAM) like ${var/$sub/"${rep}}"}. Issue #154. Bash: fix single character special parameters like $? by limiting style. Issue #154. Bash: treat "$$" as special parameter and end scalars before "$". Issue #154. Bash: treat "<<" in arithmetic contexts as left bitwise shift operator instead of here-doc. Issue #137. Batch: style SCE_BAT_AFTER_LABEL used for rest of line after label which is not executed. Issue #148. F#: Lex interpolated verbatim strings as verbatim. Issue #156. VB: allow multiline strings when lexer.vb.strings.multiline set. Issue #151. Close #13729
2023-05-31 23:11:12 +00:00
with file.open(encoding="iso-8859-1") as infile:
return [s.strip()[len(prefix):] for s in infile if s.startswith(prefix)]
def ExcludeName(name, excludes):
return any(exclude in name for exclude in excludes)
def SortLike(incs, order):
return sorted(incs, key = lambda i: order.index(i))
2019-05-04 18:14:48 +00:00
basePrefix = "//base:"
sourcePrefix = "//source:"
excludePrefix = "//exclude:"
def CheckFiles(headerOrderTxt):
headerOrderFile = pathlib.Path(headerOrderTxt).resolve()
bases = ExtractWithPrefix(headerOrderFile, basePrefix)
base = bases[0] if len(bases) > 0 else ".."
orderDirectory = headerOrderFile.parent
root = (orderDirectory / base).resolve()
# Find all the source code files
patterns = ExtractWithPrefix(headerOrderFile, sourcePrefix)
excludes = ExtractWithPrefix(headerOrderFile, excludePrefix)
filePaths = []
for p in patterns:
filePaths += root.glob(p)
headerOrder = ExtractHeaders(headerOrderFile)
originalOrder = headerOrder[:]
orderedPaths = [p for p in sorted(filePaths) if not ExcludeName(str(p), excludes)]
allIncs = set()
for f in orderedPaths:
#~ print(" File ", f.relative_to(root))
incs = ExtractHeaders(f)
allIncs = allIncs.union(set(incs))
2019-05-04 18:14:48 +00:00
m = 0
i = 0
# Detect headers not in header order list and insert at OK position
needs = []
2019-05-04 18:14:48 +00:00
while i < len(incs):
if m == len(headerOrder):
#~ print("**** extend", incs[i:])
headerOrder.extend(incs[i:])
needs.extend(incs[i:])
2019-05-04 18:14:48 +00:00
break
if headerOrder[m] == incs[i]:
#~ print("equal", headerOrder[m])
2019-05-04 18:14:48 +00:00
i += 1
m += 1
else:
if headerOrder[m] not in incs:
#~ print("skip", headerOrder[m])
2019-05-04 18:14:48 +00:00
m += 1
elif incs[i] not in headerOrder:
#~ print(str(f) + ":1: Add master", incs[i])
headerOrder.insert(m, incs[i])
needs.append(incs[i])
2019-05-04 18:14:48 +00:00
i += 1
m += 1
else:
i += 1
if needs:
print(f"{f}:1: needs these headers:")
for header in needs:
print("#include " + header)
# Detect out of order
ordered = SortLike(incs, headerOrder)
if incs != ordered:
print(f"{f}:1: is out of order")
fOrdered = pathlib.Path(str(f) + ".ordered")
with fOrdered.open("w") as headerOut:
for header in ordered:
headerOut.write("#include " + header + "\n")
print(f"{fOrdered}:1: is ordered")
if headerOrder != originalOrder:
newIncludes = set(headerOrder) - set(originalOrder)
headerOrderNew = orderDirectory / "NewOrder.txt"
print(f"{headerOrderFile}:1: changed to {headerOrderNew}")
print(f" Added {', '.join(newIncludes)}.")
with headerOrderNew.open("w") as headerOut:
for header in headerOrder:
headerOut.write("#include " + header + "\n")
unused = sorted(set(headerOrder) - allIncs)
if unused:
print("In HeaderOrder.txt but not used")
print("\n".join(unused))
2019-05-04 18:14:48 +00:00
if len(sys.argv) > 1:
CheckFiles(sys.argv[1])
else:
CheckFiles("HeaderOrder.txt")