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:
parent
9b30e2b50b
commit
8ce1b8df76
|
@ -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
|
||||
.. code-block:: c++
|
||||
someLongFunction(argument1,
|
||||
argument2);
|
||||
\endcode
|
||||
|
||||
**AlignConsecutiveAssignments** (``bool``)
|
||||
If ``true``, aligns consecutive assignments.
|
||||
|
||||
This will align the assignment operators of consecutive lines. This
|
||||
will result in formattings like
|
||||
\code
|
||||
.. code-block:: c++
|
||||
int aaaa = 12;
|
||||
int b = 23;
|
||||
int ccc = 23;
|
||||
\endcode
|
||||
|
||||
**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
|
||||
.. code-block:: c++
|
||||
FOREACH(<variable-declaration>, ...)
|
||||
<loop-body>
|
||||
\endcode
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -301,9 +301,25 @@ struct FormatStyle {
|
|||
/// <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 &&
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue