Auto Format using .clang-format file produces code that cannot be compiled

Test environment
Windows 10
IDE
Version: 2.0.0-rc1-nightly.20211211
Date: 2021-12-11T03:03:18.267Z
CLI Version: 0.20.2 [13783819]

Copyright © 2021 Arduino SA

Test sketch

void setup() { 
  updateOpenAndFilled(1,2,3,4);
}

void loop(){
}

void updateOpenAndFilled(int sourceBlockX, int sourceBlockY, int destBlockX, int destBlockY){
  //statements here
}

With only this line in the .clang-format file in the sketch folder

BreakBeforeBraces: Allman

Auto Format only works intermittently and when it does the sketch now looks like this

void setup() { updateOpenAndFilled(1, 2, 3, 4); }

void loop() {}

void updateOpenAndFilled(int sourceBlockX, int sourceBlockY, int destBlockX,
                         int destBlockY)
{
  // statements here
}

and the code cannot be compiled, giving the error

C:\Users\Bob2\AppData\Local\Temp\.arduinoIDE-unsaved20211111-8248-17idvp2.nbsd\sketch_dec11a\sketch_dec11a.ino:2:3: error: 'updateOpenAndFilled' was not declared in this scope

I know for a fact that the Allman format has worked previously and I note that for Auto Format to work the PC has to have an Internet connection, so something has changed centrally, the Language Server, perhaps, as Auto Format no longer works older versions of the 2.0 IDE either

it's likely that the IDE does not pick up the function name because of the new formatting and thus does not create the forward declaration

could you try with

void updateOpenAndFilled(int sourceBlockX, int sourceBlockY, int destBlockX, int destBlockY){
  //statements here
}

void setup() { 
  updateOpenAndFilled(1,2,3,4);
}

void loop(){
}

Good idea

I would if Auto Formatting had not stopped working completely, but in any case the BreakBeforeBraces: Allman style is not being applied

Later :
OK, Auto Format started to work again and either moving the function definition to the start of the sketch or adding an explicit function prototype manually with the actual function later in the code allows the code to be compiled

The Allman style is still not being applied though

so this seems broken and the IDE's is not smart enough to adapt to multi-line function definition apparently.

IDE 2.0 seems to move me 2 steps forward only to move 1 step back

I would like to use it as my main IDE because I like some of the things that it has to offer, but until the clang format file could be used to set the Auto Format style to at least near what I wanted I was reluctant to do so

Then the formatting was partially sorted, albeit a .clang-format file is required for each sketch (Allman format worked at that point), but the IDE misbehaved with COM ports and prevented uploads

That is now at least partially fixed, only for me to discover that Auto Formatting is broken

I realise that this is beta software but the fact that there is a Release Candidate with these problems is worrying

a good question for the video conference next week :wink:

My thoughts exactly :grinning:

Have you gotten other results with that exact code from that exact ClangFormat configuration previously? If so, which version of the Arduino IDE was it?

I get identical output if I format the code directly using the standalone LLVM clang-format tool from command line, no Arduino anything involved, so it seems like the normal result to me.

I wasn't able to reproduce it.

Please do this:

  1. Select File > Preferences from the Arduino IDE menus.
  2. Check the box next to "Show verbose output during: ☐ compilation"
  3. Click the OK button.
  4. Select Sketch > Verify/Compile from the Arduino IDE menus.
  5. Wait for the compilation to fail.

Now examine the contents of the black output pane at the bottom of the Arduino IDE window to find the location of the build folder. For example, from this output line:

"C:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-size" -A "C:\\Users\\per\\AppData\\Local\\Temp\\arduino-sketch-4C3AA61A337CEE782D8B03C336B0B525/934610.ino.elf"

I can see that my temporary build folder is at this path:

C:\Users\\per\AppData\Local\Temp\arduino-sketch-4C3AA61A337CEE782D8B03C336B0B525

Open the sketch subfolder of that path and then paste the contents of the file with the .ino.cpp file extension here.

The Arduino Language Server is bundled with each installation of the Arduino IDE, in this subfolder:

resources\app\node_modules\arduino-ide-extension\build

and the clangd language server that does the formatting is also bundled in this subfolder:

resources\app\node_modules\arduino-ide-extension\build

so I would not expect older versions of the IDE to be affected by a new installation of the IDE or by later changes to Arduino Language Server in general.

Once I found out about putting the .clang-format file in the sketch directory I experimented and the BreakBeforeBraces: Allman style of braces, ie a new line before braces, suited how I normally format code so I tested it in 2.0 rc1 and it did what I wanted, but I cannot recall having tried it beyond a trivial sketch, and certainly not with such a long line of function definition. I found the problem when trying the formatting on a much larger sketch, the function definition of which is what I gave as my example

Here is the ino.cpp file for the failed compile after Auto Format

#include <Arduino.h>
#line 1 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>

MatrixPanel_I2S_DMA *display = nullptr;

int PANEL_RES_X = 64; // Number of pixels wide of each INDIVIDUAL panel module.
int PANEL_RES_Y = 64; // Number of pixels tall of each INDIVIDUAL panel module.
int PANEL_CHAIN = 1;  // Total number of panels chained one to another

uint16_t blackTile = display->color565(0, 0, 0);        // black
uint16_t frameColour = display->color565(0, 0, 255);    // blue
uint16_t textColour = display->color565(255, 255, 255); // white

enum directions
{
  RIGHT,
  LEFT,
  UP,
  DOWN,
  NONE
};

byte oppositeDirections[] = {LEFT, RIGHT, DOWN, UP};

const byte tileSize = 9;
const int wait = 100;

const byte numOfBlocksX = 4;
const byte numOfBlocksY = 4;

struct blockData
{
  byte topLeftX;
  byte topLeftY;
  byte open = NONE;
  bool filled = true;
  int tileNumber;
};

const char tileLetters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

blockData blocks[numOfBlocksX][numOfBlocksY];

#line 43 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void setup();
#line 57 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void loop();
#line 104 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void slideBlock(byte blockX, byte blockY, int dir);
#line 166 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void setupMatrix();
#line 181 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void drawBoard();
#line 206 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void drawTile(int x, int y);
#line 213 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void clearOpens();
#line 224 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void findEmptyBlock(int &blockX, int &blockY);
#line 240 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void updateOpens();
#line 275 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void showTileLetter(int x, int y, char letter);
#line 283 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void blankTile(int x, int y);
#line 288 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void drawTileFrame(int x, int y);
#line 43 "C:\\Users\\Bob2\\Documents\\Arduino\\__matrix-panel\\_blockslide\\blockSlide44\\blockSlide44.ino"
void setup()
{
  Serial.begin(115200);
  setupMatrix();
  display->setBrightness8(32); // 0-255
  blocks[numOfBlocksX - 1][numOfBlocksY - 1].filled =
      false; // start with bottom/right empty
  blocks[numOfBlocksX - 1][numOfBlocksY - 1].open = NONE;
  blocks[numOfBlocksX - 1][numOfBlocksY - 1].tileNumber =
      -1; // tile number for empty tile
  drawBoard();
  delay(2000);
}

void loop()
{
  static byte prevDirection;
  int blockX;
  int blockY;
  findEmptyBlock(blockX, blockY); // note - pass by reference
  byte openDirections[4];         // test 4 directions around empty block
  byte openCount = 0;
  if (blockX > 0) // not at the left
  {
    openDirections[openCount++] = RIGHT;
  }
  if (blockX < numOfBlocksX - 1) // not at the right
  {
    openDirections[openCount++] = LEFT;
  }
  if (blockY > 0) // not at the top
  {
    openDirections[openCount++] = DOWN;
  }
  if (blockY < numOfBlocksY - 1) // not at the bottom
  {
    openDirections[openCount++] = UP;
  }
  byte direction = openDirections[random(openCount)];
  if (direction != oppositeDirections[prevDirection]) // prevent bounces
  {
    switch (direction)
    {
    case RIGHT:
      blockX--;
      break;
    case LEFT:
      blockX++;
      break;
    case UP:
      blockY++;
      break;
    case DOWN:
      blockY--;
      break;
    };
    slideBlock(blockX, blockY, direction);
    prevDirection = direction;
  }
}

void slideBlock(byte blockX, byte blockY, int dir)
{
  static int rightCount = 0;
  static int leftCount = 0;
  static int upCount = 0;
  static int downCount = 0;
  switch (dir)
  {
  case RIGHT:
    for (int x = blocks[blockX][blockY].topLeftX;
         x < blocks[blockX][blockY].topLeftX + tileSize; x++)
    {
      blankTile(x, blocks[blockX][blockY].topLeftY);
      drawTileFrame(x + 1, blocks[blockX][blockY].topLeftY);
      showTileLetter(x, blocks[blockX][blockY].topLeftY,
                     tileLetters[blocks[blockX][blockY].tileNumber]);
      delay(wait);
    }
    updateOpenAndFilled(blockX, blockY, blockX + 1, blockY);
    break;
  //
  case LEFT:
    for (int x = blocks[blockX][blockY].topLeftX;
         x > blocks[blockX][blockY].topLeftX - tileSize; x--)
    {
      blankTile(x, blocks[blockX][blockY].topLeftY);
      drawTileFrame(x - 1, blocks[blockX][blockY].topLeftY);
      showTileLetter(x - 2, blocks[blockX][blockY].topLeftY,
                     tileLetters[blocks[blockX][blockY].tileNumber]);
      delay(wait);
    }
    updateOpenAndFilled(blockX, blockY, blockX - 1, blockY);
    break;
  //
  case UP:
    for (int y = blocks[blockX][blockY].topLeftY;
         y > blocks[blockX][blockY].topLeftY - tileSize; y--)
    {
      blankTile(blocks[blockX][blockY].topLeftX, y);
      drawTileFrame(blocks[blockX][blockY].topLeftX, y - 1);
      showTileLetter(blocks[blockX][blockY].topLeftX - 1, y - 1,
                     tileLetters[blocks[blockX][blockY].tileNumber]);
      delay(wait);
    }
    updateOpenAndFilled(blockX, blockY, blockX, blockY - 1);
    break;
  //
  case DOWN:
    for (int y = blocks[blockX][blockY].topLeftY;
         y < blocks[blockX][blockY].topLeftY + tileSize; y++)
    {
      blankTile(blocks[blockX][blockY].topLeftX, y);
      drawTileFrame(blocks[blockX][blockY].topLeftX, y + 1);
      showTileLetter(blocks[blockX][blockY].topLeftX - 1, y + 1,
                     tileLetters[blocks[blockX][blockY].tileNumber]);
      delay(wait);
    }
    updateOpenAndFilled(blockX, blockY, blockX, blockY + 1);
    break;
  };
}

void setupMatrix()
{
  HUB75_I2S_CFG mxconfig(PANEL_RES_X, // module width
                         PANEL_RES_Y, // module height
                         PANEL_CHAIN  // Chain length
  );
  mxconfig.gpio.e = 18;
  mxconfig.clkphase = false;
  mxconfig.driver = HUB75_I2S_CFG::FM6126A;
  mxconfig.double_buff = true;
  display = new MatrixPanel_I2S_DMA(mxconfig);
  display->begin();
  display->clearScreen();
}

void drawBoard()
{
  byte tileNumber = 0;
  display->drawRect(0, 0, tileSize * numOfBlocksX + 2,
                    tileSize * numOfBlocksX + 2, frameColour);
  for (int blockY = 0; blockY < numOfBlocksY; blockY++)
  {
    for (int blockX = 0; blockX < numOfBlocksX; blockX++)
    {
      blocks[blockX][blockY].tileNumber = tileNumber++;
      blocks[blockX][blockY].topLeftX = blockX * tileSize + 1;
      blocks[blockX][blockY].topLeftY = blockY * tileSize + 1;
      if (blocks[blockX][blockY].filled)
      {
        drawTile(blocks[blockX][blockY].topLeftX,
                 blocks[blockX][blockY].topLeftY);
        showTileLetter(blocks[blockX][blockY].topLeftX - 1,
                       blocks[blockX][blockY].topLeftY,
                       tileLetters[blocks[blockX][blockY].tileNumber]);
      }
    }
  }
  updateOpens();
}

void drawTile(int x, int y)
{
  display->fillRect(x, y, tileSize, tileSize, blackTile);
  display->drawRect(x, y, tileSize, tileSize, frameColour);
  delay(wait);
}

void clearOpens()
{
  for (int blockY = 0; blockY < numOfBlocksY; blockY++)
  {
    for (int blockX = 0; blockX < numOfBlocksX; blockX++)
    {
      blocks[blockX][blockY].open = NONE; // remove current open flag
    }
  }
}

void findEmptyBlock(int &blockX, int &blockY) // NOTE - pass by reference
{
  for (int y = 0; y < numOfBlocksY; y++)
  {
    for (int x = 0; x < numOfBlocksX; x++)
    {
      if (blocks[x][y].filled == false) // found the empty tile
      {
        blockX = x;
        blockY = y;
        return;
      }
    }
  }
}

void updateOpens()
{
  clearOpens();
  int blockX;
  ;
  int blockY;
  findEmptyBlock(blockX, blockY); // note - pass by reference
  if (blockX == 0)
  {
    blocks[blockX + 1][blockY].open = LEFT;
  }
  else if (blockX == numOfBlocksX - 1)
  {
    blocks[blockX - 1][blockY].open = RIGHT;
  }
  else
  {
    blocks[blockX + 1][blockY].open = LEFT;
    blocks[blockX - 1][blockY].open = RIGHT;
  }
  if (blockY == 0)
  {
    blocks[blockX][blockY + 1].open = UP;
  }
  else if (blockY == numOfBlocksY - 1)
  {
    blocks[blockX][blockY - 1].open = DOWN;
  }
  else
  {
    blocks[blockX][blockY - 1].open = DOWN;
    blocks[blockX][blockY + 1].open = UP;
  }
}

void showTileLetter(int x, int y, char letter)
{
  display->setTextSize(0);
  display->setTextColor(textColour);
  display->setCursor(x + 3, y + 1);
  display->print(letter);
}

void blankTile(int x, int y)
{
  display->fillRect(x, y, tileSize, tileSize, blackTile);
}

void drawTileFrame(int x, int y)
{
  display->drawRect(x, y, tileSize, tileSize, frameColour);
}

void updateOpenAndFilled(int sourceBlockX, int sourceBlockY, int destBlockX,
                         int destBlockY)
{
  blocks[destBlockX][destBlockY].filled = true;      // destination is filled
  blocks[sourceBlockX][sourceBlockY].filled = false; // source block is now
                                                     // empty
  blocks[destBlockX][destBlockY].tileNumber =
      blocks[sourceBlockX][sourceBlockY].tileNumber;
  blocks[sourceBlockX][sourceBlockY].tileNumber =
      -1; // no tile number on empty tile
  updateOpens();
}

This is the reason I tried it and it bugged out and I never tried it again. I want to spend my time using tools not dancing around them. I can’t recommend Visual Micro enough if you write something bigger than blink.

I think you will be able to get pretty much any code style you want from ClangFormat, but there are a ton of options so it might take you some time to get there. Fortunately, it is the sort of thing you can do once and be done with it.

The fact that auto format produced the necessary conditions was purely coincidental. The same would occur even if you manually produced a sketch that meets the following conditions:

  • The sketch contains a function with parameter list spanning multiple lines
  • The sketch is dependent on the sketch preprocessor generating a prototype for that function
  • The sketch is in an unsaved state

I have reported the bug to the Arduino IDE developers here:

I thought that I had found most of the format options that I wanted, break before braces being the core requirement and I will continue to experiment with a smaller, less demanding sketch to start with

Good news.
More research on my part found the clang format option ColumnLimit.

Setting it to zero prevents long lines being split, which solves my problem and I can compile code with long lines without them being split and hence the compiler can create function prototypes as normal

From my point of view this issue is closed

It might, however, be a good idea to make that option a default if/when Auto Formatting is improved in the IDE to prevent further reports of the problem

Many thanks for your patient help

I still hope there will eventually be an investigation into the missing prototype generation under these conditions.

I think we will always have to accept that prototypes are not generated under more challenging or advanced use cases, but those limitations should at least apply consistently.

We can see that the system is already able to handle multi-line parameter lists. It seems that this difference in behavior with a saved vs unsaved sketch might be a symptom of a problem that is larger than the specific case you discovered.

It is already:

https://github.com/arduino/arduino-language-server/blob/0.5.0-rc7/ls/ls_formatter.go#L73

ColumnLimit: 0

I would have suggested to get rid of it and encourage beginners to write proper C++ code where you declare something before using it (seems to make sense when you think of it) - if this were not to break the zillions demo code that are out there and now rely on the IDE's feature...

This is error prone and has led generations of beginners (and more advanced programmers) to wonder what's going on because the real compiled code is not what they think it is (due to IDE code injection) and you have no control really over it...

I agree, but I have now found a difference between how the classic IDE deals with functions with default parameters and version 2.0 and I am not sure which is correct

This sketch compiles using 1.8.13

void test(int x = 0);

void setup()
{
  Serial.begin(115200);
  test();
  test(123);
}

void loop()
{
}

void test(int x = 0)
{
  Serial.println(x);
}

and is the way that I have always used functions with default parameters. However, it fails to compile using 2.0.0-rc1-nightly.20211211

Error :

C:\Users\Bob2\AppData\Local\Temp\.arduinoIDE-unsaved20211112-3876-xa8vs.u07gki\sketch_dec12a\sketch_dec12a.ino:14:20: error: default argument given for parameter 1 of 'void test(int)' [-fpermissive]
C:\Users\Bob2\AppData\Local\Temp\.arduinoIDE-unsaved20211112-3876-xa8vs.u07gki\sketch_dec12a\sketch_dec12a.ino:1:6: note: previous specification in 'void test(int)' here
 void setup() {

Changing the function to

void test(int x)
{
  Serial.println(x);
}

allows the code to be compiled. I know little or nothing about GCC but I suspect that this is the more correct form and that the classic version of the IDE and its use of GCC was more tolerant

Which version of 2.0 uses this default ?
If it is being used by 2.0.0-rc1-nightly.20211211 then it is not working

Which board are you compiling for?

ESP32 Dev Module when I tried it originally, but thinking back I strongly suspect that when I tried it in the classic IDE it was using a Nano

Just tried it using a Nano and it compiles OK in 2.0 but fails to compile with ESP32 Dev Board as the target

exit status 1
default argument given for parameter 1 of 'void test(int)' [-fpermissive]

So, the fault/discrepancy is not between the classic IDE and 2.0
My apologies

2.0.0.beta.5 and newer.

I think I understand the cause of your confusion.

The configuration shown here is the IDE's default formatter configuration:

https://github.com/arduino/arduino-language-server/blob/0.5.0-rc7/ls/ls_formatter.go#L16-L159

But that is only used when no custom configuration is supplied. Once you add a .clang-format file to the sketch, your custom configuration is used exclusively. This means that any configuration setting you don't specify in your configuration file is set to the default value provided by ClangFormat.

With your original configuration file:

BreakBeforeBraces: Allman

The effective configuration is:

$ clang-format  --dump-config 
---
Language:        Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands:   Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
  AfterCaseLabel:  true
  AfterClass:      true
  AfterControlStatement: Always
  AfterEnum:       true
  AfterFunction:   true
  AfterNamespace:  true
  AfterObjCDeclaration: true
  AfterStruct:     true
  AfterUnion:      true
  AfterExternBlock: true
  BeforeCatch:     true
  BeforeElse:      true
  BeforeLambdaBody: false
  BeforeWhile:     false
  IndentBraces:    false
  SplitEmptyFunction: true
  SplitEmptyRecord: true
  SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit:     80
CommentPragmas:  '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat:   false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
  - foreach
  - Q_FOREACH
  - BOOST_FOREACH
IncludeBlocks:   Preserve
IncludeCategories:
  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
    Priority:        2
    SortPriority:    0
  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
    Priority:        3
    SortPriority:    0
  - Regex:           '.*'
    Priority:        1
    SortPriority:    0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentWidth:     2
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd:   ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments:  true
SortIncludes:    true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles:  false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard:        Latest
StatementMacros:
  - Q_UNUSED
  - QT_REQUIRE_VERSION
TabWidth:        8
UseCRLF:         false
UseTab:          Never
WhitespaceSensitiveMacros:
  - STRINGIZE
  - PP_STRINGIZE
  - BOOST_PP_STRINGIZE
...

Note that ClangFormat's default value for ColumnLimit is 80.

Yeah, it is because the "Arduino AVR Boards" platform uses the -fpermissive compiler flag, but the ESP32 and most other board platforms do not, so you get a warning (if they are on) while compiling for one board and an error for another board:

That is being tracked here:

That makes sense
I will take the default configuration and use it as the basis for my own config.

I see that BreakBeforeBraces is set to Allman in the default, but I suspect that it is being overridden by one or more of the other options because it does not work with no .clang-format file present in the sketch directory

But in the list of IDE default clang options in reply #18 it is set to 80

Incidentally, whilst testing Auto Formatting I had another occurrence of Save As prompting whether I wanted to close the sketch. It happens too if I use Save and change the name of the sketch, so basically I cannot save the sketch either with its default name or a new name. I will try to reproduce the problem in a repeatable way so that it can be investigated

Another 2 steps forward and 1 back, or possibly 1 forward and 2 back