[clang-format] adds enclosing function detection to raw string formatting
Summary: This patch adds enclosing function detection to raw string formatting. Reviewers: bkramer Reviewed By: bkramer Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D42167 llvm-svn: 322678
This commit is contained in:
parent
2c6fe505b1
commit
2537e22094
|
@ -994,9 +994,9 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
.. code-block:: c++
|
||||
|
||||
Constructor()
|
||||
: initializer1(),
|
||||
initializer2()
|
||||
Constructor()
|
||||
: initializer1(),
|
||||
initializer2()
|
||||
|
||||
* ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``)
|
||||
Break constructor initializers before the colon and commas, and align
|
||||
|
@ -1004,18 +1004,18 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
.. code-block:: c++
|
||||
|
||||
Constructor()
|
||||
: initializer1()
|
||||
, initializer2()
|
||||
Constructor()
|
||||
: initializer1()
|
||||
, initializer2()
|
||||
|
||||
* ``BCIS_AfterColon`` (in configuration: ``AfterColon``)
|
||||
Break constructor initializers after the colon and commas.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
Constructor() :
|
||||
initializer1(),
|
||||
initializer2()
|
||||
Constructor() :
|
||||
initializer1(),
|
||||
initializer2()
|
||||
|
||||
|
||||
|
||||
|
@ -1201,7 +1201,8 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
* ``IBS_Regroup`` (in configuration: ``Regroup``)
|
||||
Merge multiple ``#include`` blocks together and sort as one.
|
||||
Then split into groups based on category priority. See ``IncludeCategories``.
|
||||
Then split into groups based on category priority. See
|
||||
``IncludeCategories``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
@ -1577,24 +1578,38 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
|
||||
**RawStringFormats** (``std::vector<RawStringFormat>``)
|
||||
Raw string delimiters denoting that the raw string contents are
|
||||
code in a particular language and can be reformatted.
|
||||
Defines hints for detecting supported languages code blocks in raw
|
||||
strings.
|
||||
|
||||
A raw string with a matching delimiter will be reformatted assuming the
|
||||
specified language based on a predefined style given by 'BasedOnStyle'.
|
||||
If 'BasedOnStyle' is not found, the formatting is based on llvm style.
|
||||
A raw string with a matching delimiter or a matching enclosing function
|
||||
name will be reformatted assuming the specified language based on the
|
||||
style for that language defined in the .clang-format file. If no style has
|
||||
been defined in the .clang-format file for the specific language, a
|
||||
predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not
|
||||
found, the formatting is based on llvm style. A matching delimiter takes
|
||||
precedence over a matching enclosing function name for determining the
|
||||
language of the raw string contents.
|
||||
|
||||
There should be at most one specification per language and each delimiter
|
||||
and enclosing function should not occur in multiple specifications.
|
||||
|
||||
To configure this in the .clang-format file, use:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
RawStringFormats:
|
||||
- Delimiter: 'pb'
|
||||
Language: TextProto
|
||||
BasedOnStyle: llvm
|
||||
- Delimiter: 'proto'
|
||||
Language: TextProto
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- 'pb'
|
||||
- 'proto'
|
||||
EnclosingFunctions:
|
||||
- 'PARSE_TEXT_PROTO'
|
||||
BasedOnStyle: google
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- 'cc'
|
||||
- 'cpp'
|
||||
BasedOnStyle: llvm
|
||||
|
||||
**ReflowComments** (``bool``)
|
||||
If ``true``, clang-format will attempt to re-flow comments.
|
||||
|
|
|
@ -1367,12 +1367,15 @@ struct FormatStyle {
|
|||
LanguageKind Language;
|
||||
/// \brief A list of raw string delimiters that match this language.
|
||||
std::vector<std::string> Delimiters;
|
||||
/// \brief A list of enclosing function names that match this language.
|
||||
std::vector<std::string> EnclosingFunctions;
|
||||
/// \brief The style name on which this raw string format is based on.
|
||||
/// If not specified, the raw string format is based on the style that this
|
||||
/// format is based on.
|
||||
std::string BasedOnStyle;
|
||||
bool operator==(const RawStringFormat &Other) const {
|
||||
return Language == Other.Language && Delimiters == Other.Delimiters &&
|
||||
EnclosingFunctions == Other.EnclosingFunctions &&
|
||||
BasedOnStyle == Other.BasedOnStyle;
|
||||
}
|
||||
};
|
||||
|
@ -1380,12 +1383,17 @@ struct FormatStyle {
|
|||
/// \brief Defines hints for detecting supported languages code blocks in raw
|
||||
/// strings.
|
||||
///
|
||||
/// A raw string with a matching delimiter will be reformatted assuming the
|
||||
/// specified language based on the style for that language defined in the
|
||||
/// .clang-format file. If no style has been defined in the .clang-format file
|
||||
/// for the specific language, a predefined style given by 'BasedOnStyle' is
|
||||
/// used. If 'BasedOnStyle' is not found, the formatting is based on llvm
|
||||
/// style.
|
||||
/// A raw string with a matching delimiter or a matching enclosing function
|
||||
/// name will be reformatted assuming the specified language based on the
|
||||
/// style for that language defined in the .clang-format file. If no style has
|
||||
/// been defined in the .clang-format file for the specific language, a
|
||||
/// predefined style given by 'BasedOnStyle' is used. If 'BasedOnStyle' is not
|
||||
/// found, the formatting is based on llvm style. A matching delimiter takes
|
||||
/// precedence over a matching enclosing function name for determining the
|
||||
/// language of the raw string contents.
|
||||
///
|
||||
/// There should be at most one specification per language and each delimiter
|
||||
/// and enclosing function should not occur in multiple specifications.
|
||||
///
|
||||
/// To configure this in the .clang-format file, use:
|
||||
/// \code{.yaml}
|
||||
|
@ -1394,6 +1402,8 @@ struct FormatStyle {
|
|||
/// Delimiters:
|
||||
/// - 'pb'
|
||||
/// - 'proto'
|
||||
/// EnclosingFunctions:
|
||||
/// - 'PARSE_TEXT_PROTO'
|
||||
/// BasedOnStyle: google
|
||||
/// - Language: Cpp
|
||||
/// Delimiters:
|
||||
|
|
|
@ -105,32 +105,44 @@ static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
|
|||
RawStringFormatStyleManager::RawStringFormatStyleManager(
|
||||
const FormatStyle &CodeStyle) {
|
||||
for (const auto &RawStringFormat : CodeStyle.RawStringFormats) {
|
||||
for (StringRef Delimiter : RawStringFormat.Delimiters) {
|
||||
llvm::Optional<FormatStyle> LanguageStyle =
|
||||
CodeStyle.GetLanguageStyle(RawStringFormat.Language);
|
||||
if (!LanguageStyle) {
|
||||
FormatStyle PredefinedStyle;
|
||||
if (!getPredefinedStyle(RawStringFormat.BasedOnStyle,
|
||||
RawStringFormat.Language, &PredefinedStyle)) {
|
||||
PredefinedStyle = getLLVMStyle();
|
||||
PredefinedStyle.Language = RawStringFormat.Language;
|
||||
}
|
||||
LanguageStyle = PredefinedStyle;
|
||||
llvm::Optional<FormatStyle> LanguageStyle =
|
||||
CodeStyle.GetLanguageStyle(RawStringFormat.Language);
|
||||
if (!LanguageStyle) {
|
||||
FormatStyle PredefinedStyle;
|
||||
if (!getPredefinedStyle(RawStringFormat.BasedOnStyle,
|
||||
RawStringFormat.Language, &PredefinedStyle)) {
|
||||
PredefinedStyle = getLLVMStyle();
|
||||
PredefinedStyle.Language = RawStringFormat.Language;
|
||||
}
|
||||
LanguageStyle->ColumnLimit = CodeStyle.ColumnLimit;
|
||||
LanguageStyle = PredefinedStyle;
|
||||
}
|
||||
LanguageStyle->ColumnLimit = CodeStyle.ColumnLimit;
|
||||
for (StringRef Delimiter : RawStringFormat.Delimiters) {
|
||||
DelimiterStyle.insert({Delimiter, *LanguageStyle});
|
||||
}
|
||||
for (StringRef EnclosingFunction : RawStringFormat.EnclosingFunctions) {
|
||||
EnclosingFunctionStyle.insert({EnclosingFunction, *LanguageStyle});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Optional<FormatStyle>
|
||||
RawStringFormatStyleManager::get(StringRef Delimiter) const {
|
||||
RawStringFormatStyleManager::getDelimiterStyle(StringRef Delimiter) const {
|
||||
auto It = DelimiterStyle.find(Delimiter);
|
||||
if (It == DelimiterStyle.end())
|
||||
return None;
|
||||
return It->second;
|
||||
}
|
||||
|
||||
llvm::Optional<FormatStyle>
|
||||
RawStringFormatStyleManager::getEnclosingFunctionStyle(
|
||||
StringRef EnclosingFunction) const {
|
||||
auto It = EnclosingFunctionStyle.find(EnclosingFunction);
|
||||
if (It == EnclosingFunctionStyle.end())
|
||||
return None;
|
||||
return It->second;
|
||||
}
|
||||
|
||||
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
|
||||
const AdditionalKeywords &Keywords,
|
||||
const SourceManager &SourceMgr,
|
||||
|
@ -1437,6 +1449,26 @@ unsigned ContinuationIndenter::handleEndOfLine(const FormatToken &Current,
|
|||
return Penalty;
|
||||
}
|
||||
|
||||
// Returns the enclosing function name of a token, or the empty string if not
|
||||
// found.
|
||||
static StringRef getEnclosingFunctionName(const FormatToken &Current) {
|
||||
// Look for: 'function(' or 'function<templates>(' before Current.
|
||||
auto Tok = Current.getPreviousNonComment();
|
||||
if (!Tok || !Tok->is(tok::l_paren))
|
||||
return "";
|
||||
Tok = Tok->getPreviousNonComment();
|
||||
if (!Tok)
|
||||
return "";
|
||||
if (Tok->is(TT_TemplateCloser)) {
|
||||
Tok = Tok->MatchingParen;
|
||||
if (Tok)
|
||||
Tok = Tok->getPreviousNonComment();
|
||||
}
|
||||
if (!Tok || !Tok->is(tok::identifier))
|
||||
return "";
|
||||
return Tok->TokenText;
|
||||
}
|
||||
|
||||
llvm::Optional<FormatStyle>
|
||||
ContinuationIndenter::getRawStringStyle(const FormatToken &Current,
|
||||
const LineState &State) {
|
||||
|
@ -1445,7 +1477,10 @@ ContinuationIndenter::getRawStringStyle(const FormatToken &Current,
|
|||
auto Delimiter = getRawStringDelimiter(Current.TokenText);
|
||||
if (!Delimiter)
|
||||
return None;
|
||||
auto RawStringStyle = RawStringFormats.get(*Delimiter);
|
||||
auto RawStringStyle = RawStringFormats.getDelimiterStyle(*Delimiter);
|
||||
if (!RawStringStyle)
|
||||
RawStringStyle = RawStringFormats.getEnclosingFunctionStyle(
|
||||
getEnclosingFunctionName(Current));
|
||||
if (!RawStringStyle)
|
||||
return None;
|
||||
RawStringStyle->ColumnLimit = getColumnLimit(State);
|
||||
|
|
|
@ -38,10 +38,14 @@ class WhitespaceManager;
|
|||
|
||||
struct RawStringFormatStyleManager {
|
||||
llvm::StringMap<FormatStyle> DelimiterStyle;
|
||||
llvm::StringMap<FormatStyle> EnclosingFunctionStyle;
|
||||
|
||||
RawStringFormatStyleManager(const FormatStyle &CodeStyle);
|
||||
|
||||
llvm::Optional<FormatStyle> get(StringRef Delimiter) const;
|
||||
llvm::Optional<FormatStyle> getDelimiterStyle(StringRef Delimiter) const;
|
||||
|
||||
llvm::Optional<FormatStyle>
|
||||
getEnclosingFunctionStyle(StringRef EnclosingFunction) const;
|
||||
};
|
||||
|
||||
class ContinuationIndenter {
|
||||
|
|
|
@ -457,6 +457,7 @@ template <> struct MappingTraits<FormatStyle::RawStringFormat> {
|
|||
static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
|
||||
IO.mapOptional("Language", Format.Language);
|
||||
IO.mapOptional("Delimiters", Format.Delimiters);
|
||||
IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
|
||||
IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
|
||||
}
|
||||
};
|
||||
|
@ -705,6 +706,12 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
|
|||
"textproto",
|
||||
"TEXTPROTO",
|
||||
},
|
||||
/*EnclosingFunctionNames=*/
|
||||
{
|
||||
"EqualsProto",
|
||||
"PARSE_TEXT_PROTO",
|
||||
"ParseTextProto",
|
||||
},
|
||||
/*BasedOnStyle=*/"google",
|
||||
}};
|
||||
GoogleStyle.SpacesBeforeTrailingComments = 2;
|
||||
|
|
|
@ -10408,8 +10408,18 @@ TEST_F(FormatTest, ParsesConfiguration) {
|
|||
|
||||
Style.RawStringFormats.clear();
|
||||
std::vector<FormatStyle::RawStringFormat> ExpectedRawStringFormats = {
|
||||
{FormatStyle::LK_TextProto, {"pb", "proto"}, "llvm"},
|
||||
{FormatStyle::LK_Cpp, {"cc", "cpp"}, "google"},
|
||||
{
|
||||
FormatStyle::LK_TextProto,
|
||||
{"pb", "proto"},
|
||||
{"PARSE_TEXT_PROTO"},
|
||||
"llvm",
|
||||
},
|
||||
{
|
||||
FormatStyle::LK_Cpp,
|
||||
{"cc", "cpp"},
|
||||
{"C_CODEBLOCK", "CPPEVAL"},
|
||||
"",
|
||||
},
|
||||
};
|
||||
|
||||
CHECK_PARSE("RawStringFormats:\n"
|
||||
|
@ -10417,12 +10427,16 @@ TEST_F(FormatTest, ParsesConfiguration) {
|
|||
" Delimiters:\n"
|
||||
" - 'pb'\n"
|
||||
" - 'proto'\n"
|
||||
" EnclosingFunctions:\n"
|
||||
" - 'PARSE_TEXT_PROTO'\n"
|
||||
" BasedOnStyle: llvm\n"
|
||||
" - Language: Cpp\n"
|
||||
" Delimiters:\n"
|
||||
" - 'cc'\n"
|
||||
" - 'cpp'\n"
|
||||
" BasedOnStyle: google\n",
|
||||
" EnclosingFunctions:\n"
|
||||
" - 'C_CODEBLOCK'\n"
|
||||
" - 'CPPEVAL'\n",
|
||||
RawStringFormats, ExpectedRawStringFormats);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,23 +65,32 @@ protected:
|
|||
FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) {
|
||||
FormatStyle Style = getLLVMStyle();
|
||||
Style.ColumnLimit = ColumnLimit;
|
||||
Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_TextProto,
|
||||
/*Delimiters=*/{"pb"},
|
||||
/*BasedOnStyle=*/"google"}};
|
||||
Style.RawStringFormats = {
|
||||
{/*Language=*/FormatStyle::LK_TextProto,
|
||||
/*Delimiters=*/{"pb"},
|
||||
/*EnclosingFunctions=*/{},
|
||||
/*BasedOnStyle=*/"google"},
|
||||
};
|
||||
return Style;
|
||||
}
|
||||
|
||||
FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) {
|
||||
FormatStyle Style = getLLVMStyle();
|
||||
Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp,
|
||||
/*Delimiters=*/{"cpp"}, BasedOnStyle}};
|
||||
Style.RawStringFormats = {
|
||||
{/*Language=*/FormatStyle::LK_Cpp,
|
||||
/*Delimiters=*/{"cpp"},
|
||||
/*EnclosingFunctions=*/{}, BasedOnStyle},
|
||||
};
|
||||
return Style;
|
||||
}
|
||||
|
||||
FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) {
|
||||
FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
|
||||
Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp,
|
||||
/*Delimiters=*/{"cpp"}, BasedOnStyle}};
|
||||
Style.RawStringFormats = {
|
||||
{/*Language=*/FormatStyle::LK_Cpp,
|
||||
/*Delimiters=*/{"cpp"},
|
||||
/*EnclosingFunctions=*/{}, BasedOnStyle},
|
||||
};
|
||||
return Style;
|
||||
}
|
||||
|
||||
|
@ -122,7 +131,7 @@ TEST_F(FormatTestRawStrings, UsesConfigurationOverBaseStyle) {
|
|||
EXPECT_EQ(0, parseConfiguration("---\n"
|
||||
"Language: Cpp\n"
|
||||
"BasedOnStyle: Google", &Style).value());
|
||||
Style.RawStringFormats = {{FormatStyle::LK_Cpp, {"cpp"}, "llvm"}};
|
||||
Style.RawStringFormats = {{FormatStyle::LK_Cpp, {"cpp"}, {}, "llvm"}};
|
||||
expect_eq(R"test(int* i = R"cpp(int* j = 0;)cpp";)test",
|
||||
format(R"test(int * i = R"cpp(int * j = 0;)cpp";)test", Style));
|
||||
}
|
||||
|
@ -720,6 +729,29 @@ TEST_F(FormatTestRawStrings, DontFormatNonRawStrings) {
|
|||
getRawStringPbStyleWithColumns(20)));
|
||||
}
|
||||
|
||||
TEST_F(FormatTestRawStrings, FormatsRawStringsWithEnclosingFunctionName) {
|
||||
FormatStyle Style = getRawStringPbStyleWithColumns(40);
|
||||
Style.RawStringFormats[0].EnclosingFunctions.push_back(
|
||||
"PARSE_TEXT_PROTO");
|
||||
Style.RawStringFormats[0].EnclosingFunctions.push_back("ParseTextProto");
|
||||
expect_eq(R"test(a = PARSE_TEXT_PROTO(R"(key: value)");)test",
|
||||
format(R"test(a = PARSE_TEXT_PROTO(R"(key:value)");)test", Style));
|
||||
|
||||
expect_eq(R"test(
|
||||
a = PARSE_TEXT_PROTO /**/ (
|
||||
/**/ R"(key: value)");)test",
|
||||
format(R"test(
|
||||
a = PARSE_TEXT_PROTO/**/(/**/R"(key:value)");)test",
|
||||
Style));
|
||||
|
||||
expect_eq(R"test(
|
||||
a = ParseTextProto<ProtoType>(
|
||||
R"(key: value)");)test",
|
||||
format(R"test(
|
||||
a = ParseTextProto<ProtoType>(R"(key:value)");)test",
|
||||
Style));
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
} // end namespace format
|
||||
} // end namespace clang
|
||||
|
|
Loading…
Reference in New Issue