This is an archive of the discontinued LLVM Phabricator instance.

[clang-format] Add style to separate definition blocks
ClosedPublic

Authored by ksyx on Dec 27 2021, 9:19 AM.

Details

Summary

This commit resolves GitHub issue #45895 (Bugzilla #46550), to add empty line between definition blocks including namespaces, classes, enums, and structs.

Diff Detail

Event Timeline

ksyx requested review of this revision.Dec 27 2021, 9:19 AM
ksyx created this revision.
ksyx added a comment.EditedDec 27 2021, 9:25 AM

Test code:

// test.cpp
#include <algorithm>
#include <cstdio>
#include <cstring>
struct Foo {
  int a,b,c;
};
namespace Ns {
class Bar {
public:
  struct Foobar {
    int a;
    int b;
  };
private:
  int t;
  int method1()
  {
    // Intentional test for different
    // line breaking mode of brackets
  }
  template<typename T>
  int method2(T x) {
    // ...
  }
  int method3(int par) {}
};
class C {
};
}
namespace Ns2 {

}

Tests ran:

# pwd = build directory
bin/clang-format test.cpp # LLVM Style
bin/clang-format -style='{SeparateDefinitionBlocks: false}' test.cpp # Disable functionality
bin/clang-format -style='{BasedOnStyle: Google}' test.cpp # Disable by default
bin/clang-format -style='{BasedOnStyle: Google, SeparateDefinitionBlocks: true}' test.cpp # Override default
bin/clang-format -style='{BasedOnStyle: WebKit}' test.cpp # Opening bracket in new line (WebKit style has this functionality enabled)
ksyx updated this revision to Diff 396321.Dec 27 2021, 9:37 AM

Apply clang-format suggestions

ksyx added inline comments.Dec 27 2021, 11:24 AM
clang/lib/Format/Format.cpp
1209

Not so sure about this as it would break some tests.

ksyx added inline comments.Dec 27 2021, 11:29 AM
clang/lib/Format/Format.cpp
1209

As CI shows some original tests does not expect this empty line, but it looks like LLVM is generally adding empty lines between blocks.

cpp
 template <typename T> class B;
+
 class A {
 public:
   int f();
-};
+};\n
ksyx updated this revision to Diff 396344.EditedDec 27 2021, 2:05 PM

Fix missing semicolon in sample/test code

ksyx edited the summary of this revision. (Show Details)Dec 27 2021, 2:06 PM
MyDeveloperDay requested changes to this revision.Dec 27 2021, 3:39 PM
MyDeveloperDay added inline comments.
clang/lib/Format/Format.cpp
1209

This needs to be an enumeration where leave is the default

This revision now requires changes to proceed.Dec 27 2021, 3:39 PM
ksyx updated this revision to Diff 396358.EditedDec 27 2021, 6:32 PM
ksyx marked an inline comment as done.
  • Change bool type of the option to enum type
  • Generate empty line for enum block

Testfile:

// test2.cpp
#include <algorithm>
#include <cstdio>
#include <cstring>
struct Foo {
  int a,b,c;
};
namespace Ns {
class Bar {
public:
  struct Foobar {
    int a;
    int b;
  };
private:
  int t;
  int method1()
  {
    // Intentional test for different
    // line breaking mode of brackets
  }
  template<typename T>
  int method2(T x) {
    // ...
  }
  enum Foo {
    FOO,
    BAR
  };
  int method3(int par) {}
};
class C {
};
}
namespace Ns2 {

}

Tests:

bin/clang-format test2.cpp # Test default (leave as it is)
bin/clang-format -style='{SeparateDefinitionBlocks: Between}' test2.cpp # Test normal functionality
bin/clang-format -style='{SeparateDefinitionBlocks: Leave}' test2.cpp # Test turning off
bin/clang-format -style='{SeparateDefinitionBlocks: Between, BasedOnStyle: WebKit}' test2.cpp # Case: opening bracket { has its own line
curdeius requested changes to this revision.Dec 28 2021, 4:31 AM

Thanks for working on this.
Please add unit tests that verify the expected behaviour. Keep them simple. You can inspire yourself from existing tests.

clang/docs/ClangFormatStyleOptions.rst
3405

Unless it takes a lot of time to review this patch 🙂

clang/lib/Format/Format.cpp
2026

Please consider moving it to a different file.

This revision now requires changes to proceed.Dec 28 2021, 4:31 AM
MyDeveloperDay added inline comments.Dec 28 2021, 7:25 AM
clang/docs/ClangFormatStyleOptions.rst
3411

This enumeration surely needs 3 settings

Leave,     // don't touch the code, if I have a line leave it alone if not don't add one
Always,   // always add a line
Never,    // never add a line and remove the lint if one exists
MyDeveloperDay retitled this revision from [Clangfmt] Add style to separate definition blocks to [clang-format] Add style to separate definition blocks.Dec 28 2021, 7:32 AM
clang/lib/Format/Format.cpp
2026

Yes please.

2113

Why only add the first replacement?

ksyx updated this revision to Diff 396421.Dec 28 2021, 12:39 PM
ksyx marked 4 inline comments as done.
  • Change version from 15 to 14
  • Add option SDS_Never, rename SDS_Between => SDS_Always
  • Add unit tests
  • Separate class into new file
ksyx marked an inline comment as done.Dec 28 2021, 12:48 PM
ksyx added inline comments.
clang/lib/Format/Format.cpp
2113

This worked well as the Error class add method returned has overloaded boolean operator, returning true (nonzero) when failing, which simulates program exit code scheme? (ref: Doxygen/Error/operator bool)

clang/include/clang/Format/Format.h
3058

Add full stop at the end of sentences.

clang/lib/Format/DefinitionBlockSeparator.cpp
56

Here also full stop, please. And following comments.

clang/lib/Format/DefinitionBlockSeparator.h
39–40

I know you copied it. It is wrong where you copied it from. :)

clang/lib/Format/Format.cpp
2113

Okay, but maybe safe the result in Error to make it clearer.

ksyx updated this revision to Diff 396428.Dec 28 2021, 1:38 PM
ksyx marked 5 inline comments as done.
  • Apply suggestions from clangfmt
  • Add missing period of comments
  • Fix namespace ending comment
  • Add comment for notes on return value of WhitespaceManager's method
ksyx updated this revision to Diff 396430.Dec 28 2021, 1:44 PM
ksyx added a comment.Dec 28 2021, 1:44 PM

Fix typo.

curdeius requested changes to this revision.Dec 29 2021, 2:31 AM

Nice job. Some minor comments.
Please don't forget to reformat too.

clang/docs/ClangFormatStyleOptions.rst
3422

Keep it consistent please.

3425

Please reformat the code, e.g. on the left misses spaces (near braces and commas for instance). The difference between left and right should only be blank lines between blocks.
Of course, do it in Format.h and regenerate the RST.

clang/include/clang/Format/Format.h
3058
3067

Why not C and other similar languages?
Also, you don't seem to be limiting the pass to C++. Please add some tests to other languages.

3069

Actuay, do you need this line?

4094
4096

?

clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
49

Maybe you can add verifyFormat helper as in other files? So that you don't need to repeat the code in some cases and we test the code formatting stability as well.

This revision now requires changes to proceed.Dec 29 2021, 2:31 AM
clang/lib/Format/DefinitionBlockSeparator.h
39–40

Not done.

ksyx updated this revision to Diff 396574.Dec 29 2021, 3:23 PM
ksyx marked 9 inline comments as done.
ksyx edited the summary of this revision. (Show Details)
  • Improve compatibility to other languages
  • Improve unit test by test format stability, inverse result, and generate some input from expected output
  • Reformat sample code
  • Use more concise word for SDS_Leave
ksyx updated this revision to Diff 396575.Dec 29 2021, 3:52 PM

Apply clangfmt's suggestions

ksyx updated this revision to Diff 396577.Dec 29 2021, 4:21 PM

Apply suggestion from clangfmt

clang/include/clang/Format/Format.h
3108–3109
clang/lib/Format/DefinitionBlockSeparator.cpp
56

Not done. :)

ksyx updated this revision to Diff 396709.Dec 30 2021, 12:53 PM
ksyx marked 2 inline comments as done.

minor fixes.

HazardyKnusperkeks requested changes to this revision.Dec 30 2021, 2:17 PM

Only some small changes, then it looks good to me. And I will definitely use it, once it is landed.

clang/include/clang/Format/Format.h
3060

Right?

4102

The only use of this function I found is in the tests and it sets the argument, or am I mistaken?

clang/lib/Format/DefinitionBlockSeparator.cpp
34–35

It should never be instantiated with that.

36
60
64
77
81
94
129
clang/lib/Format/Format.cpp
464

Please try to find a better place, regarding sorting (yeah the are some mismatches).

786

Please sort before ShortNamespaceLines

3062
clang/lib/Format/WhitespaceManager.h
48
This revision now requires changes to proceed.Dec 30 2021, 2:17 PM
ksyx updated this revision to Diff 396727.Dec 30 2021, 4:04 PM
ksyx marked 9 inline comments as done.
  • Apply review suggestions.
  • Assert the style is not SDS_Leave in private method, while return no change in public method if so.
  • Rename loop variable Line to CurrentLine
clang/include/clang/Format/Format.h
4102

I suppose this function might also be called from some users of the library other than clangfmt itself? Besides, the declarations nearby are setting this default value.

clang/lib/Format/DefinitionBlockSeparator.cpp
36

Some other lambdas I found use lowercased leading letter, as it looks like a function (call).

clang/lib/Format/DefinitionBlockSeparator.cpp
26

Better, but I still think we should have the assert here. The class should not be instantiated at all, if you don't want to use it.

36

Okay, then I don't know what the LLVM Style is, probably there is none in this regard. I think the lambdas I saw in clang-format are with a capital letter.

ksyx updated this revision to Diff 396781.Dec 31 2021, 5:41 AM
ksyx marked 5 inline comments as done.

Change lambda variable names' leading letter to uppercase.

ksyx updated this revision to Diff 396782.Dec 31 2021, 5:43 AM

Change lambda variable names' leading letter to uppercase.

clang/lib/Format/DefinitionBlockSeparator.cpp
26

My idea is that it would be too redundant to have every user of this method to check style once before it calls it?

36

Ok. Then I will make changes.

clang/lib/Format/DefinitionBlockSeparator.cpp
26

Who are the users? clang-format and maybe its tests. And the only one that really matters is clang-format, which does the check.

clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
46

Maybe one should either use the normal reformat function, or additionally. Because right now we do not test any interferences of these two functions.

ksyx updated this revision to Diff 396826.Dec 31 2021, 2:21 PM

Use reformat method instead of calling the single method only.

ksyx marked an inline comment as done.Dec 31 2021, 2:22 PM
ksyx added inline comments.
clang/lib/Format/DefinitionBlockSeparator.cpp
26

Does there exist the possibility that some developer just include the header and link to library to obtain replacement analysis result for their other parts of program to use, instead of only clangfmt itself is using this class?

clang/lib/Format/DefinitionBlockSeparator.cpp
26

Of course the possibility exists, but I don't think there is anyone. And at least for me those aren't the audience. And even then, they can make sure that it's not SDS_Leave.

ksyx updated this revision to Diff 396835.Dec 31 2021, 4:01 PM
ksyx marked 3 inline comments as done.

Change the SDS_Leave style check to be assert not having this style.

MyDeveloperDay accepted this revision.Jan 1 2022, 3:35 AM

LGTM thank you for this patch, I'll also definately use this myself.

clang/docs/ClangFormatStyleOptions.rst
3405

EmptyLinesBetweenBlocks?

ksyx added inline comments.Jan 1 2022, 5:49 AM
clang/docs/ClangFormatStyleOptions.rst
3405

It feel like for me that it is implying that there will also be empty lines surrounding blocks of, for example, for and if?

Can you add a release note to docs/ReleaseNotes.rst

ksyx updated this revision to Diff 396926.Jan 2 2022, 6:24 AM

Add release note entry.

curdeius accepted this revision.Jan 3 2022, 3:28 AM

LGTM.

This revision is now accepted and ready to land.Jan 3 2022, 12:29 PM
This revision was landed with ongoing or failed builds.Jan 3 2022, 12:50 PM
This revision was automatically updated to reflect the committed changes.
MyDeveloperDay added a comment.EditedJan 4 2022, 2:13 AM

I'm seeing some odd behaviour here..

void foo() {}
/* ABC */
void bar() {}

becomes

void foo() {}

/* ABC */

void bar() {}

If the ABC comment is a doxygen style comment it doesn't make sense to separate it from the function below

logged as https://github.com/llvm/llvm-project/issues/52976

@ksyx

Did you see this issue https://github.com/llvm/llvm-project/issues/52976

In its current form, this patch causes huge amounts of flux in projects
that document code like (anyone using doxygen likely, + most normal people
;-) )

...
}

// My function
<<<<-------- extra newline added
void
foo()
{
}

as it will place and undesirable additional newline between the function
and the return type.

We really need this to be resolved before we branch out v14 (which may be
imminent)

MyDeveloperDay

ksyx added a comment.Jan 5 2022, 7:31 AM

@ksyx

Did you see this issue https://github.com/llvm/llvm-project/issues/52976

In its current form, this patch causes huge amounts of flux in projects
that document code like (anyone using doxygen likely, + most normal people
;-) )

...
}

// My function
<<<<-------- extra newline added
void
foo()
{
}

as it will place and undesirable additional newline between the function
and the return type.

We really need this to be resolved before we branch out v14 (which may be
imminent)

MyDeveloperDay

Thanks for the feedback! I have proposed some fix in D116663, and please see if this works.