clang-format for Rider not working properly

Hi, I am trying out Rider for Unreal Engine, and one of the most important aspects for me is to be able to use my clang-format files.

I currently have a .clang-format file in the main project directory, however it seems that Rider is just not picking it up no matter what I try.

 

Ill note that I am on the Windows platform and trying to migrate over from Visual Studio with Visual Assist X.

I have built clang-format.exe myself from LLVM 10.0, and it works find with vscode and Visual Studio.

It is also exposed in my PATH as well, and clang-format can be called from any command prompt.

 

My clang-format file looks like this:

StatementMacros: ['UPROPERTY', 'UCLASS', 'USTRUCT', 'GENERATED_BODY', 'UENUM']

Language: Cpp
Standard: c++20
ColumnLimit: 140
IndentWidth: 4
TabWidth: 4
AccessModifierOffset: -4
UseTab: AlignWithSpaces
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4

PointerAlignment: Left
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: false
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
AlignTrailingComments: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: Never
AllowShortBlocksOnASingleLine: Empty
AllowShortLambdasOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false

BinPackArguments: true
BinPackParameters: true

#BitFieldColonSpacing: Both

BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: true
BeforeLambdaBody: true
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true

BreakBeforeBinaryOperators: NonAssignment
#BreakBeforeConceptDeclarations: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: false
CompactNamespaces: false
Cpp11BracedListStyle: true
FixNamespaceComments: true

IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^.*\.generated\.h'
Priority: 99999
- Regex: '<[[:alnum:].]+>'
Priority: 2
- Regex: '.*'
Priority: 1
SortPriority: 0

IndentCaseBlocks: false
IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: false
#IndentPPDirectives: false
#IndentRequires: false
IndentWrappedFunctionNames: false
#InsertTrailingCommas: Wrapped

#MacroBlockBegin: []
SortUsingDeclarations: true

SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
#SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 3
SpacesInAngles: true
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: true
SpacesInContainerLiterals: true
SpacesInParentheses: true
SpacesInSquareBrackets: false

 

When I go into `Editor > Code Style` I can see that Enable Clang-Format support is on.

If I hit the `Export` button, the path it shows to export is the exact same path of my current clang-format file, however the contents it wants to write out are a brand new style based off of LLVM.

Clang-format support is incredibly important for me and a definite deal-breaker in terms of using Rider for Unreal.

I would argue that there should be an option to completely disable the build in Formatting entirely if clang-format is detected.

11 comments
Comment actions Permalink

Hello,

There's duplicated AllowAllParametersOfDeclarationOnNextLine in your .clang-format which confuses Rider. We'll fix this, but please remove one of the AllowAllParametersOfDeclarationOnNextLine as a workaround for now.

Rider does not use clang-format directly, instead it takes your .clang-format and tries to translate it into Rider's own formatting settings.

Thanks!

0
Comment actions Permalink

Thanks, @..., removing the duplicate line has made it work. However the following statement has already proven problematic.


> Rider does not use clang-format directly, instead it takes your .clang-format and tries to translate it into Rider's own formatting settings.

After removing the duplicate line and testing it out, there are clear discrepancies between what clang-format would product and what Rider produces - This does not work well at all especially with a CI pipeline that enforces strict formatting. Multiple people, using different editors, we can all at least get the code to agree with clang-format. But Rider's interpretation of the clang-format file doesn't seem to match everything.

Visual studio delegates all formatting work to clang-format when found - why can't Rider do the same?

I understand being able to import a clang-format file as Rider code formatting decisions is nice, but that should be an option.

If there is a clang-format executable and the user has specified a .clang-format file, it should use the executable and only fallback to Rider's formatting if the executable is not found, or the user has disabled clang-format.

0
Comment actions Permalink

Just another note on the importance of actually using the clang-format executable - I have encountered a few projects that ship their own specific version of clang-format due to needing new/old formatting behavior and keeping everything consistent.

This is also why visual studio has an option to manually specify the clang-format.exe path.

0
Comment actions Permalink

We don't have plans to replace our formatter with clang-format at the moment, however we definitely want to improve our compatibility. If you notice some particular .clang-format settings that are imported with problems, please let us know.

0
Comment actions Permalink

Rider doesn't need to replace the formatter, it just needs to delegate the responsibility in the presence of clang-format.

ie:

If a .clang-format file exists, and clang-format.exe exists, then all formatting should be invoked via clang-format. Othwerse, fall back to Rider's formatting.

0
Comment actions Permalink

Hello Marios

Regarding the delegation to the clang-format.exe - you can use the File Watchers (Settings-> Tools -> File Watchers) to call the executable directly on file changes. Note that you might want to disable " Auto-save edited files to trigger the watcher" and/or "Trigger the watcher on external changes" depending on your workflow.

I'm attaching the example configuration below - in this example Rider will call clang-format that is available in PATH, but you can also set the path to the executable manually via "Browse". In addition to that, note that this example uses a scope that includes all .cpp files in the source directory of the game.

You can find out more about File Watchers and scopes in the documentation.

Let me know if you have any questions.

0
Comment actions Permalink

Hi Kirill Filin,

thanks for that information, I was able to get decent behavior with two file watches (for c++ headers and source files separately) and adding clang-format as an external tool as well, with a custom keybind.

This almost gives me native-esque behavior, and will seem to solve my issues with CI rejecting changes due to style differences.

That being said, as a primary c++ developer with a lot of experience across code bases, I doubt I will be the only one that uses clang-format - and I think it would be in the best interest of everyone to get this implemented correctly.

From what I can infer (I haven't tested it myself) CLion already does this correctly (https://www.jetbrains.com/help/clion/clangformat-as-alternative-formatter.html) and has all of its formatting completely overridden by clang-format when present.

0
Comment actions Permalink

I've been using the file watcher method for a while now, and while it works, it has really proven to be annoying. When you undo after a file watcher format, it asks to reload the file from disk. As someone who saves a lot during their work, it is a popup I constantly run into.

I would really like to see a better built in solution that using a file watcher.

0
Comment actions Permalink

FYI, to get rid of the "Undo reload from disk" prompt, add $FilePath$ to "Output paths to refresh".

0
Comment actions Permalink

Hello there,

We want to share the latest news regarding clang-format support in Rider. We are currently working on supporting external clang-format binaries in Rider (without the file watcher). This feature will not land in the upcoming Rider 2022.1, but we plan to implement it in future releases.

Thanks for your feedback.

0
Comment actions Permalink

I have also encountered this issue. When formatting a file using Rider, the result is often different to when using clang-format directly or through Visual Studio. Since we have some team members using the latter approach, this is very problematic for us.

I have tried using the ClangFormatIJ plugin and this works, but it cannot be hooked up to a save action (needs to be run manually through the Actions menu). I have not yet tried the file watcher method described above but this sounds promising.

If needed I can provide details on the precise formatting discrepancies we have encountered, but if real clang-format integration is already planned then I suspect this is not necessary.

0

Please sign in to leave a comment.