Skip to content

Commit 4613cfd

Browse files
committed
Standardize ClangFormat configuration file format
The LLVM/Clang/ClangFormat project is under very active development, with configuration keys regularly being added, changed to a different data type, or removed. When a key is set in the configuration file, the default LLVM style value is used. This means that updating to a new version of ClangFormat might result in unintended changes to the results from the configuration file. In the case of a change of type, it seems the ClangFormat developers generally will provide backwards compatibility of some sort, but there is no guarantee that the resulting configuration will be exactly the same as was intended when the value of the key was selected for use in Arduino's configuration file. ClangFormat has a useful `--dump-config` flag which outputs the effective configuration. This allows us to determine whether there are any differences between the intended configuration as defined by Arduino's configuration file and the actual configuration of the tool. In order to accomplish this, it is best to use the exact format output by `clang-format --dump-config`, which allows any differences to be detected and seen clearly using a simple diff command. The only exception is the insertion of a comment providing the source URL of the configuration file in order to facilitate the syncing of changes with the downstream copies of the file in the various projects that use it.
1 parent 6f774b2 commit 4613cfd

File tree

7 files changed

+208
-60
lines changed

7 files changed

+208
-60
lines changed

.ecrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"__pycache__[/\\\\]",
66
"node_modules[/\\\\]",
77
"^other[/\\\\]clang-format-configuration[/\\\\]testdata[/\\\\]",
8+
"^other[/\\\\]clang-format-configuration[/\\\\]\\.clang-format",
89
"^LICENSE\\.txt$",
910
"^poetry\\.lock$"
1011
]

.github/workflows/check-clang-format.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,65 @@ jobs:
5858
- name: Validate ClangFormat configuration files
5959
run: task --silent clang-format:validate
6060

61+
check-config:
62+
runs-on: ubuntu-latest
63+
64+
steps:
65+
- name: Checkout repository
66+
uses: actions/checkout@v3
67+
68+
- name: Install Task
69+
uses: arduino/setup-task@v1
70+
with:
71+
repo-token: ${{ secrets.GITHUB_TOKEN }}
72+
version: 3.x
73+
74+
- name: Set environment variables
75+
run: |
76+
# See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable
77+
if [[ "${{ github.event.inputs.clang-format-version }}" == "" ]]; then
78+
echo "CLANG_FORMAT_VERSION=$(task clang-format:get-version)" >> "$GITHUB_ENV"
79+
else
80+
echo "CLANG_FORMAT_VERSION=${{ github.event.inputs.clang-format-version }}" >> "$GITHUB_ENV"
81+
fi
82+
echo "CLANG_FORMAT_INSTALL_PATH=${{ runner.temp }}/clang-format" >> "$GITHUB_ENV"
83+
echo "WORKING_FOLDER=${{ runner.temp }}" >> "$GITHUB_ENV"
84+
85+
- name: Download ClangFormat
86+
id: download
87+
uses: MrOctopus/[email protected]
88+
with:
89+
repository: arduino/clang-static-binaries
90+
tag: ${{ env.CLANG_FORMAT_VERSION }}
91+
asset: clang-format_${{ env.CLANG_FORMAT_VERSION }}_Linux_64bit.tar.bz2
92+
target: ${{ env.CLANG_FORMAT_INSTALL_PATH }}
93+
94+
- name: Install ClangFormat
95+
run: |
96+
cd "${{ env.CLANG_FORMAT_INSTALL_PATH }}"
97+
tar --extract --file="${{ steps.download.outputs.name }}"
98+
# Add installation to PATH:
99+
# See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path
100+
echo "${{ env.CLANG_FORMAT_INSTALL_PATH }}/clang_Linux_64bit" >> "$GITHUB_PATH"
101+
102+
- name: Check ClangFormat configuration file
103+
id: check
104+
run: |
105+
task \
106+
--silent \
107+
clang-format:check-config \
108+
CLANG_FORMAT_VERSION="${{ env.CLANG_FORMAT_VERSION }}"
109+
110+
- name: Save effective configuration file to a workflow artifact
111+
if: >
112+
always() &&
113+
steps.check.outcome == 'failure'
114+
uses: actions/upload-artifact@v3
115+
with:
116+
path: ${{ env.WORKING_FOLDER }}/expected/.clang-format
117+
if-no-files-found: error
118+
name: config-output
119+
61120
check-output:
62121
runs-on: ubuntu-latest
63122

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ __pycache__/
33
node_modules/
44
/other/clang-format-configuration/testdata/golden/samples/
55
/other/clang-format-configuration/testdata/input/samples/
6+
/other/clang-format-configuration/.clang-format

.yamllint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,6 @@ yaml-files:
7272

7373
ignore: |
7474
/.git/
75+
/other/clang-format-configuration/.clang-format
7576
__pycache__/
7677
node_modules/

Taskfile.yml

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tasks:
1717
desc: Check for problems with the project
1818
deps:
1919
- task: ci:validate
20+
- task: clang-format:check-config
2021
- task: clang-format:check-output
2122
- task: clang-format:check-testdata
2223
- task: clang-format:validate
@@ -111,6 +112,32 @@ tasks:
111112
-s "{{.WORKFLOW_SCHEMA_PATH}}" \
112113
-d "{{.TEMPLATE_WORKFLOWS_DATA_PATH}}"
113114
115+
clang-format:check-config:
116+
desc: Check that ClangFormat configuration file matches effective tool configuration
117+
vars:
118+
WORKING_FOLDER:
119+
sh: |
120+
if [[ "{{.WORKING_FOLDER}}" == "" ]]; then
121+
# Generate a path
122+
task utility:mktemp-folder TEMPLATE="clang-format-check-config-XXXXXXXXXX"
123+
else
124+
# A path was specified via the command line
125+
echo "{{.WORKING_FOLDER}}"
126+
fi
127+
ACTUAL_CONFIGURATION_PATH: "{{.WORKING_FOLDER}}/actual/.clang-format"
128+
EXPECTED_CONFIGURATION_PATH: "{{.WORKING_FOLDER}}/expected/.clang-format"
129+
cmds:
130+
- |
131+
mkdir "{{.WORKING_FOLDER}}/actual"
132+
mkdir "{{.WORKING_FOLDER}}/expected"
133+
cp "{{.CLANG_FORMAT_CONFIGURATION_PATH}}" "{{.WORKING_FOLDER}}/actual/"
134+
- task: clang-format:dump-config
135+
vars:
136+
TARGET_PATH: "{{.WORKING_FOLDER}}/expected/.clang-format"
137+
- |
138+
cd "{{.WORKING_FOLDER}}"
139+
diff --color=always --unified "actual/.clang-format" "expected/.clang-format"
140+
114141
# Check if ClangFormat is installed and the expected version
115142
clang-format:check-installed:
116143
vars:
@@ -198,6 +225,23 @@ tasks:
198225
"{{.CLANG_FORMAT_CONFIGURATION_PATH}}" \
199226
"{{.OUTPUT_PATH}}"
200227
228+
# Write the effective ClangFormat configuration to the path specified by the TARGET_PATH variable
229+
clang-format:dump-config:
230+
deps:
231+
- task: clang-format:check-installed
232+
cmds:
233+
- |
234+
# Add source comment
235+
echo \
236+
"# Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration" > \
237+
"{{.TARGET_PATH}}"
238+
239+
# Dump the effective configuration to the target file
240+
clang-format \
241+
--dump-config \
242+
--style=file:"{{.CLANG_FORMAT_CONFIGURATION_PATH}}" >> \
243+
"{{.TARGET_PATH}}"
244+
201245
# Use ClangFormat to format the files under the path specified by TARGET_FOLDER recursively
202246
clang-format:format:
203247
cmds:
@@ -226,6 +270,13 @@ tasks:
226270
cmds:
227271
- echo "{{.DEFAULT_CLANG_FORMAT_VERSION}}"
228272

273+
clang-format:update-config:
274+
desc: Update ClangFormat configuration file to match effective tool configuration
275+
cmds:
276+
- task: clang-format:dump-config
277+
vars:
278+
TARGET_PATH: "{{.CLANG_FORMAT_CONFIGURATION_PATH}}"
279+
229280
clang-format:update-golden:
230281
desc: Update golden master test data for current configuration
231282
deps:
@@ -276,7 +327,6 @@ tasks:
276327
"{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/general/.editorconfig" \
277328
"{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/check-python/.flake8" \
278329
"{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/check-markdown/.markdownlint.yml" \
279-
"{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/check-yaml/.yamllint.yml" \
280330
"{{.REPOSITORY_ROOT_PATH}}"
281331
282332
dependabot:validate:
Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
# Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration
22
---
3-
Language: Cpp
4-
BasedOnStyle: LLVM
3+
Language: Cpp
54
AccessModifierOffset: -2
65
AlignAfterOpenBracket: Align
6+
AlignConsecutiveMacros: false
77
AlignConsecutiveAssignments: false
88
AlignConsecutiveBitFields: false
99
AlignConsecutiveDeclarations: false
10-
AlignConsecutiveMacros: false
1110
AlignEscapedNewlines: DontAlign
12-
AlignOperands: Align
11+
AlignOperands: Align
1312
AlignTrailingComments: true
1413
AllowAllArgumentsOnNextLine: true
1514
AllowAllConstructorInitializersOnNextLine: true
1615
AllowAllParametersOfDeclarationOnNextLine: true
16+
AllowShortEnumsOnASingleLine: true
1717
AllowShortBlocksOnASingleLine: Always
1818
AllowShortCaseLabelsOnASingleLine: true
19-
AllowShortEnumsOnASingleLine: true
2019
AllowShortFunctionsOnASingleLine: Empty
21-
AllowShortIfStatementsOnASingleLine: Always
2220
AllowShortLambdasOnASingleLine: Empty
21+
AllowShortIfStatementsOnASingleLine: Always
2322
AllowShortLoopsOnASingleLine: true
2423
AlwaysBreakAfterDefinitionReturnType: None
2524
AlwaysBreakAfterReturnType: None
@@ -28,70 +27,82 @@ AlwaysBreakTemplateDeclarations: No
2827
BinPackArguments: true
2928
BinPackParameters: true
3029
BraceWrapping:
31-
AfterCaseLabel: false
32-
AfterClass: false
30+
AfterCaseLabel: false
31+
AfterClass: false
3332
AfterControlStatement: Never
34-
AfterEnum: false
35-
AfterFunction: false
36-
AfterNamespace: false
37-
#AfterObjCDeclaration:
38-
AfterStruct: false
39-
AfterUnion: false
33+
AfterEnum: false
34+
AfterFunction: false
35+
AfterNamespace: false
36+
AfterObjCDeclaration: false
37+
AfterStruct: false
38+
AfterUnion: false
4039
AfterExternBlock: false
41-
BeforeCatch: false
42-
BeforeElse: false
40+
BeforeCatch: false
41+
BeforeElse: false
4342
BeforeLambdaBody: false
44-
BeforeWhile: false
45-
IndentBraces: false
46-
SplitEmptyFunction: false
47-
SplitEmptyRecord: false
48-
SplitEmptyNamespace: false
49-
#BreakAfterJavaFieldAnnotations:
43+
BeforeWhile: false
44+
IndentBraces: false
45+
SplitEmptyFunction: true
46+
SplitEmptyRecord: true
47+
SplitEmptyNamespace: true
5048
BreakBeforeBinaryOperators: NonAssignment
5149
BreakBeforeBraces: Attach
50+
BreakBeforeInheritanceComma: false
51+
BreakInheritanceList: BeforeColon
5252
BreakBeforeTernaryOperators: true
53+
BreakConstructorInitializersBeforeComma: false
5354
BreakConstructorInitializers: BeforeColon
54-
BreakInheritanceList: BeforeColon
55+
BreakAfterJavaFieldAnnotations: false
5556
BreakStringLiterals: false
56-
ColumnLimit: 0
57-
CommentPragmas: ""
57+
ColumnLimit: 0
58+
CommentPragmas: ''
5859
CompactNamespaces: false
5960
ConstructorInitializerAllOnOneLineOrOnePerLine: true
6061
ConstructorInitializerIndentWidth: 2
6162
ContinuationIndentWidth: 2
6263
Cpp11BracedListStyle: false
6364
DeriveLineEnding: true
6465
DerivePointerAlignment: true
65-
DisableFormat: false
66-
#ExperimentalAutoDetectBinPacking:
66+
DisableFormat: false
67+
ExperimentalAutoDetectBinPacking: false
6768
FixNamespaceComments: false
68-
ForEachMacros: []
69-
IncludeBlocks: Preserve
70-
IncludeCategories: []
71-
IncludeIsMainRegex: ""
72-
IncludeIsMainSourceRegex: ""
73-
IndentCaseBlocks: true
69+
ForEachMacros:
70+
- foreach
71+
- Q_FOREACH
72+
- BOOST_FOREACH
73+
IncludeBlocks: Preserve
74+
IncludeCategories:
75+
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
76+
Priority: 2
77+
SortPriority: 0
78+
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
79+
Priority: 3
80+
SortPriority: 0
81+
- Regex: '.*'
82+
Priority: 1
83+
SortPriority: 0
84+
IncludeIsMainRegex: ''
85+
IncludeIsMainSourceRegex: ''
7486
IndentCaseLabels: true
75-
IndentExternBlock: Indent
87+
IndentCaseBlocks: true
7688
IndentGotoLabels: false
7789
IndentPPDirectives: None
78-
IndentWidth: 2
90+
IndentExternBlock: Indent
91+
IndentWidth: 2
7992
IndentWrappedFunctionNames: false
8093
InsertTrailingCommas: None
81-
#JavaImportGroups:
82-
#JavaScriptQuotes:
83-
#JavaScriptWrapImports:
94+
JavaScriptQuotes: Leave
95+
JavaScriptWrapImports: true
8496
KeepEmptyLinesAtTheStartOfBlocks: true
85-
MacroBlockBegin: ""
86-
MacroBlockEnd: ""
97+
MacroBlockBegin: ''
98+
MacroBlockEnd: ''
8799
MaxEmptyLinesToKeep: 100000
88100
NamespaceIndentation: None
89-
NamespaceMacros: []
90-
#ObjCBinPackProtocolList:
91-
#ObjCBlockIndentWidth:
92-
#ObjCBreakBeforeNestedBlockParam:
93-
#ObjCSpaceAfterProperty:
94-
#ObjCSpaceBeforeProtocolList:
101+
ObjCBinPackProtocolList: Auto
102+
ObjCBlockIndentWidth: 2
103+
ObjCBreakBeforeNestedBlockParam: true
104+
ObjCSpaceAfterProperty: false
105+
ObjCSpaceBeforeProtocolList: true
95106
PenaltyBreakAssignment: 1
96107
PenaltyBreakBeforeFirstCallParameter: 1
97108
PenaltyBreakComment: 1
@@ -101,9 +112,8 @@ PenaltyBreakTemplateDeclaration: 1
101112
PenaltyExcessCharacter: 1
102113
PenaltyReturnTypeOnItsOwnLine: 1
103114
PointerAlignment: Right
104-
RawStringFormats: []
105-
ReflowComments: false
106-
SortIncludes: false
115+
ReflowComments: false
116+
SortIncludes: false
107117
SortUsingDeclarations: false
108118
SpaceAfterCStyleCast: false
109119
SpaceAfterLogicalNot: false
@@ -114,20 +124,26 @@ SpaceBeforeCtorInitializerColon: true
114124
SpaceBeforeInheritanceColon: true
115125
SpaceBeforeParens: ControlStatements
116126
SpaceBeforeRangeBasedForLoopColon: true
117-
SpaceBeforeSquareBrackets: false
118127
SpaceInEmptyBlock: false
119128
SpaceInEmptyParentheses: false
120129
SpacesBeforeTrailingComments: 2
121-
SpacesInAngles: false
122-
SpacesInCStyleCastParentheses: false
130+
SpacesInAngles: false
123131
SpacesInConditionalStatement: false
124132
SpacesInContainerLiterals: false
133+
SpacesInCStyleCastParentheses: false
125134
SpacesInParentheses: false
126135
SpacesInSquareBrackets: false
127-
Standard: Auto
128-
StatementMacros: []
129-
TabWidth: 2
130-
TypenameMacros: []
131-
UseCRLF: false
132-
UseTab: Never
133-
WhitespaceSensitiveMacros: []
136+
SpaceBeforeSquareBrackets: false
137+
Standard: Auto
138+
StatementMacros:
139+
- Q_UNUSED
140+
- QT_REQUIRE_VERSION
141+
TabWidth: 2
142+
UseCRLF: false
143+
UseTab: Never
144+
WhitespaceSensitiveMacros:
145+
- STRINGIZE
146+
- PP_STRINGIZE
147+
- BOOST_PP_STRINGIZE
148+
...
149+

0 commit comments

Comments
 (0)