You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
11 KiB
415 lines
11 KiB
|
|
Preprocessor blocks can arbitrarily alter the program flow and make indenting
|
|
code a challenging task.
|
|
|
|
This file covers the following topics:
|
|
1) Uncrustify approach to indentation of preprocessor blocks
|
|
2) Rationale for the chosen approach
|
|
3) Recommendations for the user
|
|
|
|
|
|
---------------------------------------------------------
|
|
Uncrustify approach to indentation of preprocessor blocks
|
|
---------------------------------------------------------
|
|
|
|
Uncrustify handles different preprocessor blocks in different ways.
|
|
There are just three simple rules to remember.
|
|
|
|
A. #ifdef/#endif block
|
|
----------------------
|
|
The contents of the block are indented starting at the same brace level of the
|
|
code preceding the block. Once #endif is reached, any indentation change caused
|
|
by the block is discarded and the following code continues at the same brace
|
|
level of the code preceding the block.
|
|
|
|
B. #ifdef/#elif/#else/#endif block
|
|
----------------------------------
|
|
The contents of the #ifdef part of the block are indented starting at the same
|
|
brace level of the code preceding the block.
|
|
Once an #elif/#else is reached, the indentation restarts at the brace level of
|
|
the code preceding the #ifdef part of the block. This is repeated for each
|
|
#else and #elif part.
|
|
Once #endif is reached, the following code continues at the same brace level
|
|
reached at the end of the #ifdef part.
|
|
|
|
C. #define block
|
|
----------------
|
|
The contents of the block are indented starting anew, therefore not following the
|
|
indentation of the code preceding the block. Once the #define ends, any indentation
|
|
change caused by the block is discarded and the following code continues at the same
|
|
brace level of the code preceding the block.
|
|
|
|
|
|
---------------------------------
|
|
Rationale for the chosen approach
|
|
---------------------------------
|
|
|
|
Preprocessor blocks can be very hard to handle and there is no definitive
|
|
correct way that works in all situations. Therefore a compromise approach is
|
|
required, coupled with warning to the user when tricky code is encountered.
|
|
|
|
A. #ifdef/#endif block
|
|
----------------------
|
|
Let's start with the simplest case, a balanced #ifdef/#endif block. This is a
|
|
block that starts and ends at the same brace level. For example:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
some code B
|
|
#endif
|
|
some code C
|
|
|
|
or
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
}
|
|
#endif
|
|
some code C
|
|
|
|
These cases are very easy to handle, since the indentation before, through and after
|
|
the preprocessor block is consistent. There is no alteration of the brace level
|
|
from 'some code A' to 'some code C'. Rule A applies nicely to the above code.
|
|
|
|
Let's now look at a more complex example.
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
#endif
|
|
some code C
|
|
#ifdef TEST
|
|
some code D
|
|
}
|
|
#endif
|
|
some code E
|
|
|
|
This contains two unbalanced #ifdef blocks. Most likely the programmer intended to
|
|
use them in pair, but that is not important when it comes to indentation. The code
|
|
above could be indented as:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
#endif
|
|
some code C
|
|
#ifdef TEST
|
|
some code D
|
|
}
|
|
#endif
|
|
some code E
|
|
|
|
or as:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
#endif
|
|
some code C
|
|
#ifdef TEST
|
|
some code D
|
|
}
|
|
#endif
|
|
some code E
|
|
|
|
Note how 'some code C' is indented differently in the two cases: in the first, the
|
|
indentation change caused by the first #ifdef block is discarded, while in the
|
|
second it is taken into consideration.
|
|
Depending on the options used at compile time, the code in the preprocessor blocks
|
|
could be included or not included in the final code, therefore none of the two
|
|
options is superior to the other. A better approach would be to avoid the use
|
|
of unbalanced preprocessor blocks, so that indentation of the code could be uniquely
|
|
defined.
|
|
Uncrustify follows the first version, discarding indentation changes caused by
|
|
the #ifdef block. Warning messages about unbalanced preprocessor blocks can optionally
|
|
be printed by using the option 'pp_warn_unbalanced_if'.
|
|
|
|
B. #ifdef/#elif/#else/#endif block
|
|
----------------------------------
|
|
Let's start with the simplest case, a balanced #ifdef/#else/#endif block. This is a
|
|
block where each part starts and ends at the same brace level. For example:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
some code B
|
|
#else
|
|
some code C
|
|
#endif
|
|
some code D
|
|
|
|
or
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
}
|
|
#else
|
|
{
|
|
some code C
|
|
}
|
|
#endif
|
|
some code D
|
|
|
|
or even:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
}
|
|
#else
|
|
some code C
|
|
#endif
|
|
some code D
|
|
|
|
These cases are very easy to handle, since the indentation before, through and after
|
|
the preprocessor blocks is consistent. There is no alteration of the brace level
|
|
from 'some code A' to 'some code D'. Rule B applies nicely to the above code.
|
|
|
|
Let's now look at a more complex example.
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
#else
|
|
some code C
|
|
#endif
|
|
some code D
|
|
#ifdef TEST
|
|
some code E
|
|
}
|
|
#else
|
|
some code F
|
|
#endif
|
|
some code G
|
|
|
|
This once again raises the question of where 'some code D' should be placed and
|
|
there is no unique best choice.
|
|
Uncrustify has chosen (for reasons explained further below) to:
|
|
- indent each part of an #ifdef/#elif/#else/#endif block starting at the brace
|
|
level of the code preceding #ifdef.
|
|
- continue after #endif at the indentation level reached at the end of the #ifdef
|
|
part.
|
|
This would result in the following formatted code:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
{
|
|
some code B
|
|
#else
|
|
some code C
|
|
#endif
|
|
some code D
|
|
#ifdef TEST
|
|
some code E
|
|
}
|
|
#else
|
|
some code F
|
|
#endif
|
|
some code G
|
|
|
|
And yes, the indentation of 'some code F' may surprise you a bit.
|
|
Here is an even trickier example:
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
some code B
|
|
#else
|
|
{
|
|
some code C
|
|
#endif
|
|
some code D
|
|
#ifndef TEST
|
|
some code E
|
|
}
|
|
#else
|
|
some code F
|
|
#endif
|
|
some code G
|
|
|
|
which results in this bizarre output, where 'some code G' is no
|
|
longer aligned with 'some code A':
|
|
|
|
some code A
|
|
#ifdef TEST
|
|
some code B
|
|
#else
|
|
{
|
|
some code C
|
|
#endif
|
|
some code D
|
|
#ifndef TEST
|
|
some code E
|
|
}
|
|
#else
|
|
some code F
|
|
#endif
|
|
some code G
|
|
|
|
So why not simply discard all the indentation changes created by an
|
|
#ifdef/#elif/#else/#endif block? The answer is simple: to make sure things
|
|
still work fine after the #endif line! Without going into too much detail here
|
|
(see the overview.odt and theory.txt files for more info) in addition to the
|
|
visible braces, there is a thing called 'virtual braces' which also affects
|
|
indentation. A common use of #ifdef/#elif/#else/#endif blocks is to do some
|
|
different things on the same set of variables. In this case, there may not be
|
|
any visible brace, but virtual braces may get modified between the code before
|
|
and after the preprocessor block. Throwing away the whole thing would result
|
|
in the code after #endif being formatted in a completely wrong manner.
|
|
As an example, consider this piece of code:
|
|
|
|
some code A
|
|
if (cond1)
|
|
some var = value1;
|
|
else
|
|
some var =
|
|
#ifdef TEST
|
|
value2;
|
|
#else
|
|
value3;
|
|
#endif
|
|
some code B
|
|
|
|
The formatted version looks exactly like the original. But if the complete
|
|
#ifdef/#else/#endif block was thrown away, the result would be as if 'some code B'
|
|
was being indented as part of the else (not #else) block, at a position just after
|
|
the = symbol. By retaining the changes made in the #ifdef part, the 'else' block
|
|
is correctly handled and 'some code B' is indented as per its original position.
|
|
|
|
C. #define block
|
|
----------------
|
|
Here is an example showing how #define works. The following code:
|
|
|
|
{
|
|
{
|
|
some code A
|
|
#define TEST \
|
|
{ \
|
|
some defs \
|
|
}
|
|
some code B
|
|
}
|
|
}
|
|
|
|
would be formatted as:
|
|
|
|
{
|
|
{
|
|
some code A
|
|
#define TEST \
|
|
{ \
|
|
some defs \
|
|
}
|
|
some code B
|
|
}
|
|
}
|
|
|
|
Notice how 'some code B' and 'some code A' are indented in the same way, while the
|
|
#define body starts from anew.
|
|
|
|
|
|
----------------------------
|
|
Recommendations for the user
|
|
----------------------------
|
|
The golden rule is to avoid unbalanced preprocessor blocks. This keeps things
|
|
simple and indentation can be uniquely defined. Existing unbalanced blocks should
|
|
be reworked so that all braces are properly balanced, either outside or inside the
|
|
preprocessor blocks.
|
|
If you have a huge code base, it may be difficult to quickly find offending blocks.
|
|
If the option 'pp_warn_unbalanced_if' is set to true, Uncrustify will print warning
|
|
messages at the end of each unbalanced preprocessor block part based on the following rules:
|
|
|
|
1) unbalanced #ifdef part
|
|
This works for either an #ifdef/#endif block or the first part of an #ifdef/#elif/#else/#endif
|
|
block. If the #ifdef ends at a brace level different from where it starts, a message will
|
|
be displayed, highlighting both the starting and ending indentation levels.
|
|
|
|
2) unbalanced #elif or #else part
|
|
If such part ends at a different brace level than the corresponding #ifdef part, a message
|
|
will be displayed highlighting the ending indentation levels of both the part in question
|
|
and the respective #ifdef part.
|
|
|
|
3) unbalanced #define
|
|
If a #define ends at a brace level different from where it starts, a message will
|
|
be displayed, highlighting the ending indentation level.
|
|
|
|
Here is an example with a mix of balanced and unbalanced blocks, with line numbers in front
|
|
for easier reference:
|
|
|
|
1 void Fun(int &data)
|
|
2 {
|
|
3 data = 1;
|
|
4
|
|
5 #ifdef MANUAL_LAYOUT
|
|
6 {
|
|
7 data = 2;
|
|
8 }
|
|
9 #endif
|
|
10
|
|
11 #ifdef MANUAL_LAYOUT
|
|
12 {
|
|
13 {
|
|
14 data = 2;
|
|
15 #elif TEST1
|
|
16 data = 21;
|
|
17 #elif TEST2
|
|
18 {
|
|
19 data = 22;
|
|
20 #elif TEST3
|
|
21 {
|
|
22 {
|
|
23 data = 22;
|
|
24 #else
|
|
25 {
|
|
26 {
|
|
27 data = 22;
|
|
28 #endif
|
|
29
|
|
30 data = 3;
|
|
31
|
|
32 #ifdef MANUAL_LAYOUT
|
|
33 {
|
|
34 data = 4;
|
|
35 #else
|
|
36 data = 5;
|
|
37 #endif
|
|
38
|
|
39 #ifdef MANUAL_LAYOUT
|
|
40 data = 6;
|
|
41 #else
|
|
42 data = 7;
|
|
43 #endif
|
|
44
|
|
45 #ifdef MANUAL_LAYOUT
|
|
46 }
|
|
47 }
|
|
48 #endif
|
|
49
|
|
50 #ifdef MANUAL_LAYOUT
|
|
51 }
|
|
52 #endif
|
|
53
|
|
54 data = 8;
|
|
55
|
|
56 data = 9;
|
|
57 }
|
|
|
|
These are the warning messages related to unbalanced preprocessor blocks
|
|
printed by Uncrustify when 'pp_warn_unbalanced_if' is true.
|
|
|
|
check(236): orig line is 15, unbalanced #if block braces (1), in-level is 1, out-level is 3
|
|
check(248): orig line is 17, unbalanced #if-#else block braces (1), #else out-level is 1, #if out-level is 3
|
|
check(248): orig line is 20, unbalanced #if-#else block braces (1), #else out-level is 2, #if out-level is 3
|
|
check(236): orig line is 35, unbalanced #if block braces (1), in-level is 3, out-level is 4
|
|
check(291): orig line is 37, unbalanced #if-#else block braces (2), #else out-level is 3, #if out-level is 4
|
|
check(321): orig line is 48, unbalanced #if block braces (2), in-level is 4, out-level is 2
|
|
check(321): orig line is 52, unbalanced #if block braces (2), in-level is 4, out-level is 3
|
|
|