clang-format: Make IncludeCategories configurable in .clang-format file.

This was made much easier by introducing an IncludeCategory struct to
replace the previously used std::pair.

Also, cleaned up documentation and added examples.

llvm-svn: 249392
This commit is contained in:
Daniel Jasper 2015-10-06 11:54:18 +00:00
parent 9b30e2b50b
commit 8ce1b8df76
5 changed files with 104 additions and 32 deletions

View File

@ -155,21 +155,29 @@ the configuration (without a prefix: ``Auto``).
This applies to round brackets (parentheses), angle brackets and square
brackets. This will result in formattings like
\code
someLongFunction(argument1,
argument2);
\endcode
.. code-block:: c++
someLongFunction(argument1,
argument2);
**AlignConsecutiveAssignments** (``bool``)
If ``true``, aligns consecutive assignments.
This will align the assignment operators of consecutive lines. This
will result in formattings like
\code
int aaaa = 12;
int b = 23;
int ccc = 23;
\endcode
.. code-block:: c++
int aaaa = 12;
int b = 23;
int ccc = 23;
**AlignConsecutiveDeclarations** (``bool``)
If ``true``, aligns consecutive declarations.
This will align the declaration names of consecutive lines. This
will result in formattings like
.. code-block:: c++
int aaaa = 12;
float b = 23;
std::string ccc = 23;
**AlignEscapedNewlinesLeft** (``bool``)
If ``true``, aligns escaped newlines as far left as possible.
@ -381,14 +389,17 @@ the configuration (without a prefix: ``Auto``).
instead of as function calls.
These are expected to be macros of the form:
\code
FOREACH(<variable-declaration>, ...)
<loop-body>
\endcode
.. code-block:: c++
FOREACH(<variable-declaration>, ...)
<loop-body>
In the .clang-format configuration file, this can be configured like:
.. code-block:: c++
ForEachMacros: ['RANGES_FOR', 'FOREACH']
For example: BOOST_FOREACH.
**IncludeCategories** (``std::vector<std::pair<std::string, unsigned>>``)
**IncludeCategories** (``std::vector<IncludeCategory>``)
Regular expressions denoting the different #include categories used
for ordering #includes.
@ -403,6 +414,16 @@ the configuration (without a prefix: ``Auto``).
so that it is kept at the beginning of the #includes
(http://llvm.org/docs/CodingStandards.html#include-style).
To configure this in the .clang-format file, use:
.. code-block:: c++
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)'
Priority: 3
- Regex: '.\*'
Priority: 1
**IndentCaseLabels** (``bool``)
Indent case labels one level from the switch statement.

View File

@ -86,7 +86,11 @@ class EnumValue:
doxygen2rst(indent(self.comment, 2)))
def clean_comment_line(line):
return line[3:].strip() + '\n'
if line == '/// \\code':
return '.. code-block:: c++\n'
if line == '/// \\endcode':
return ''
return line[4:] + '\n'
def read_options(header):
class State:
@ -139,8 +143,6 @@ def read_options(header):
elif line == '};':
state = State.InStruct
nested_structs[nested_struct.name] = nested_struct
else:
raise Exception('Invalid format, expected struct field comment or };')
elif state == State.InNestedFieldComent:
if line.startswith('///'):
comment += clean_comment_line(line)
@ -168,7 +170,7 @@ def read_options(header):
for option in options:
if not option.type in ['bool', 'unsigned', 'int', 'std::string',
'std::vector<std::string>',
'std::vector<std::pair<std::string, unsigned>>']:
'std::vector<IncludeCategory>']:
if enums.has_key(option.type):
option.enum = enums[option.type]
elif nested_structs.has_key(option.type):

View File

@ -48,8 +48,8 @@ struct FormatStyle {
/// This applies to round brackets (parentheses), angle brackets and square
/// brackets. This will result in formattings like
/// \code
/// someLongFunction(argument1,
/// argument2);
/// someLongFunction(argument1,
/// argument2);
/// \endcode
bool AlignAfterOpenBracket;
@ -58,9 +58,9 @@ struct FormatStyle {
/// This will align the assignment operators of consecutive lines. This
/// will result in formattings like
/// \code
/// int aaaa = 12;
/// int b = 23;
/// int ccc = 23;
/// int aaaa = 12;
/// int b = 23;
/// int ccc = 23;
/// \endcode
bool AlignConsecutiveAssignments;
@ -69,9 +69,9 @@ struct FormatStyle {
/// This will align the declaration names of consecutive lines. This
/// will result in formattings like
/// \code
/// int aaaa = 12;
/// float b = 23;
/// std::string ccc = 23;
/// int aaaa = 12;
/// float b = 23;
/// std::string ccc = 23;
/// \endcode
bool AlignConsecutiveDeclarations;
@ -297,13 +297,29 @@ struct FormatStyle {
///
/// These are expected to be macros of the form:
/// \code
/// FOREACH(<variable-declaration>, ...)
/// <loop-body>
/// FOREACH(<variable-declaration>, ...)
/// <loop-body>
/// \endcode
///
/// In the .clang-format configuration file, this can be configured like:
/// \code
/// ForEachMacros: ['RANGES_FOR', 'FOREACH']
/// \endcode
///
/// For example: BOOST_FOREACH.
std::vector<std::string> ForEachMacros;
/// \brief See documentation of \c IncludeCategories.
struct IncludeCategory {
/// \brief The regular expression that this category matches.
std::string Regex;
/// \brief The priority to assign to this category.
unsigned Priority;
bool operator==(const IncludeCategory &Other) const {
return Regex == Other.Regex && Priority == Other.Priority;
}
};
/// \brief Regular expressions denoting the different #include categories used
/// for ordering #includes.
///
@ -317,7 +333,18 @@ struct FormatStyle {
/// category. The main header for a source file automatically gets category 0,
/// so that it is kept at the beginning of the #includes
/// (http://llvm.org/docs/CodingStandards.html#include-style).
std::vector<std::pair<std::string, unsigned>> IncludeCategories;
///
/// To configure this in the .clang-format file, use:
/// \code
/// IncludeCategories:
/// - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
/// Priority: 2
/// - Regex: '^(<|"(gtest|isl|json)/)'
/// Priority: 3
/// - Regex: '.*'
/// Priority: 1
/// \endcode
std::vector<IncludeCategory> IncludeCategories;
/// \brief Indent case labels one level from the switch statement.
///
@ -546,6 +573,7 @@ struct FormatStyle {
ExperimentalAutoDetectBinPacking ==
R.ExperimentalAutoDetectBinPacking &&
ForEachMacros == R.ForEachMacros &&
IncludeCategories == R.IncludeCategories &&
IndentCaseLabels == R.IndentCaseLabels &&
IndentWidth == R.IndentWidth && Language == R.Language &&
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&

View File

@ -37,6 +37,7 @@
using clang::format::FormatStyle;
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
namespace llvm {
namespace yaml {
@ -247,6 +248,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
IO.mapOptional("ForEachMacros", Style.ForEachMacros);
IO.mapOptional("IncludeCategories", Style.IncludeCategories);
IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
IO.mapOptional("IndentWidth", Style.IndentWidth);
IO.mapOptional("IndentWrappedFunctionNames",
@ -307,6 +309,13 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
}
};
template <> struct MappingTraits<FormatStyle::IncludeCategory> {
static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) {
IO.mapOptional("Regex", Category.Regex);
IO.mapOptional("Priority", Category.Priority);
}
};
// Allows to read vector<FormatStyle> while keeping default values.
// IO.getContext() should contain a pointer to the FormatStyle structure, that
// will be used to get default values for missing keys.
@ -1737,8 +1746,8 @@ tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
// Create pre-compiled regular expressions for the #include categories.
SmallVector<llvm::Regex, 4> CategoryRegexs;
for (const auto &IncludeBlock : Style.IncludeCategories)
CategoryRegexs.emplace_back(IncludeBlock.first);
for (const auto &Category : Style.IncludeCategories)
CategoryRegexs.emplace_back(Category.Regex);
for (;;) {
auto Pos = Code.find('\n', SearchFrom);
@ -1753,7 +1762,7 @@ tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
Category = UINT_MAX;
for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i) {
if (CategoryRegexs[i].match(Matches[1])) {
Category = Style.IncludeCategories[i].second;
Category = Style.IncludeCategories[i].Priority;
break;
}
}

View File

@ -9646,6 +9646,8 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,
FormatStyle::NI_All);
// FIXME: This is required because parsing a configuration simply overwrites
// the first N elements of the list instead of resetting it.
Style.ForEachMacros.clear();
std::vector<std::string> BoostForeach;
BoostForeach.push_back("BOOST_FOREACH");
@ -9655,6 +9657,16 @@ TEST_F(FormatTest, ParsesConfiguration) {
BoostAndQForeach.push_back("Q_FOREACH");
CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,
BoostAndQForeach);
Style.IncludeCategories.clear();
std::vector<FormatStyle::IncludeCategory> ExpectedCategories = {{"abc/.*", 2},
{".*", 1}};
CHECK_PARSE("IncludeCategories:\n"
" - Regex: abc/.*\n"
" Priority: 2\n"
" - Regex: .*\n"
" Priority: 1",
IncludeCategories, ExpectedCategories);
}
TEST_F(FormatTest, ParsesConfigurationWithLanguages) {