r322956 - [clang-format] Adds a canonical delimiter to raw string formatting
Krasimir Georgiev via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 19 08:18:47 PST 2018
Author: krasimir
Date: Fri Jan 19 08:18:47 2018
New Revision: 322956
URL: http://llvm.org/viewvc/llvm-project?rev=322956&view=rev
Log:
[clang-format] Adds a canonical delimiter to raw string formatting
Summary:
This patch adds canonical delimiter support to the raw string formatting.
This allows matching delimiters to be updated to the canonical one.
Reviewers: bkramer
Reviewed By: bkramer
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D42187
Modified:
cfe/trunk/docs/ClangFormatStyleOptions.rst
cfe/trunk/include/clang/Format/Format.h
cfe/trunk/lib/Format/ContinuationIndenter.cpp
cfe/trunk/lib/Format/Format.cpp
cfe/trunk/unittests/Format/FormatTest.cpp
cfe/trunk/unittests/Format/FormatTestRawStrings.cpp
Modified: cfe/trunk/docs/ClangFormatStyleOptions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ClangFormatStyleOptions.rst?rev=322956&r1=322955&r2=322956&view=diff
==============================================================================
--- cfe/trunk/docs/ClangFormatStyleOptions.rst (original)
+++ cfe/trunk/docs/ClangFormatStyleOptions.rst Fri Jan 19 08:18:47 2018
@@ -1590,6 +1590,9 @@ the configuration (without a prefix: ``A
precedence over a matching enclosing function name for determining the
language of the raw string contents.
+ If a canonical delimiter is specified, occurences of other delimiters for
+ the same language will be updated to the canonical if possible.
+
There should be at most one specification per language and each delimiter
and enclosing function should not occur in multiple specifications.
@@ -1610,6 +1613,7 @@ the configuration (without a prefix: ``A
- 'cc'
- 'cpp'
BasedOnStyle: llvm
+ CanonicalDelimiter: 'cc'
**ReflowComments** (``bool``)
If ``true``, clang-format will attempt to re-flow comments.
Modified: cfe/trunk/include/clang/Format/Format.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=322956&r1=322955&r2=322956&view=diff
==============================================================================
--- cfe/trunk/include/clang/Format/Format.h (original)
+++ cfe/trunk/include/clang/Format/Format.h Fri Jan 19 08:18:47 2018
@@ -1369,6 +1369,8 @@ struct FormatStyle {
std::vector<std::string> Delimiters;
/// \brief A list of enclosing function names that match this language.
std::vector<std::string> EnclosingFunctions;
+ /// \brief The canonical delimiter for this language.
+ std::string CanonicalDelimiter;
/// \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.
@@ -1376,6 +1378,7 @@ struct FormatStyle {
bool operator==(const RawStringFormat &Other) const {
return Language == Other.Language && Delimiters == Other.Delimiters &&
EnclosingFunctions == Other.EnclosingFunctions &&
+ CanonicalDelimiter == Other.CanonicalDelimiter &&
BasedOnStyle == Other.BasedOnStyle;
}
};
@@ -1392,6 +1395,9 @@ struct FormatStyle {
/// precedence over a matching enclosing function name for determining the
/// language of the raw string contents.
///
+ /// If a canonical delimiter is specified, occurences of other delimiters for
+ /// the same language will be updated to the canonical if possible.
+ ///
/// There should be at most one specification per language and each delimiter
/// and enclosing function should not occur in multiple specifications.
///
@@ -1410,6 +1416,7 @@ struct FormatStyle {
/// - 'cc'
/// - 'cpp'
/// BasedOnStyle: llvm
+ /// CanonicalDelimiter: 'cc'
/// \endcode
std::vector<RawStringFormat> RawStringFormats;
Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=322956&r1=322955&r2=322956&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Fri Jan 19 08:18:47 2018
@@ -102,6 +102,18 @@ static llvm::Optional<StringRef> getRawS
return Delimiter;
}
+// Returns the canonical delimiter for \p Language, or the empty string if no
+// canonical delimiter is specified.
+static StringRef
+getCanonicalRawStringDelimiter(const FormatStyle &Style,
+ FormatStyle::LanguageKind Language) {
+ for (const auto &Format : Style.RawStringFormats) {
+ if (Format.Language == Language)
+ return StringRef(Format.CanonicalDelimiter);
+ }
+ return "";
+}
+
RawStringFormatStyleManager::RawStringFormatStyleManager(
const FormatStyle &CodeStyle) {
for (const auto &RawStringFormat : CodeStyle.RawStringFormats) {
@@ -1312,14 +1324,32 @@ unsigned ContinuationIndenter::reformatR
const FormatToken &Current, LineState &State,
const FormatStyle &RawStringStyle, bool DryRun) {
unsigned StartColumn = State.Column - Current.ColumnWidth;
- auto Delimiter = *getRawStringDelimiter(Current.TokenText);
+ StringRef OldDelimiter = *getRawStringDelimiter(Current.TokenText);
+ StringRef NewDelimiter =
+ getCanonicalRawStringDelimiter(Style, RawStringStyle.Language);
+ if (NewDelimiter.empty() || OldDelimiter.empty())
+ NewDelimiter = OldDelimiter;
// The text of a raw string is between the leading 'R"delimiter(' and the
// trailing 'delimiter)"'.
- unsigned PrefixSize = 3 + Delimiter.size();
- unsigned SuffixSize = 2 + Delimiter.size();
+ unsigned OldPrefixSize = 3 + OldDelimiter.size();
+ unsigned OldSuffixSize = 2 + OldDelimiter.size();
+ // We create a virtual text environment which expects a null-terminated
+ // string, so we cannot use StringRef.
+ std::string RawText =
+ Current.TokenText.substr(OldPrefixSize).drop_back(OldSuffixSize);
+ if (NewDelimiter != OldDelimiter) {
+ // Don't update to the canonical delimiter 'deli' if ')deli"' occurs in the
+ // raw string.
+ std::string CanonicalDelimiterSuffix = (")" + NewDelimiter + "\"").str();
+ if (StringRef(RawText).contains(CanonicalDelimiterSuffix))
+ NewDelimiter = OldDelimiter;
+ }
+
+ unsigned NewPrefixSize = 3 + NewDelimiter.size();
+ unsigned NewSuffixSize = 2 + NewDelimiter.size();
- // The first start column is the column the raw text starts.
- unsigned FirstStartColumn = StartColumn + PrefixSize;
+ // The first start column is the column the raw text starts after formatting.
+ unsigned FirstStartColumn = StartColumn + NewPrefixSize;
// The next start column is the intended indentation a line break inside
// the raw string at level 0. It is determined by the following rules:
@@ -1330,7 +1360,7 @@ unsigned ContinuationIndenter::reformatR
// These rules have the advantage that the formatted content both does not
// violate the rectangle rule and visually flows within the surrounding
// source.
- bool ContentStartsOnNewline = Current.TokenText[PrefixSize] == '\n';
+ bool ContentStartsOnNewline = Current.TokenText[OldPrefixSize] == '\n';
unsigned NextStartColumn = ContentStartsOnNewline
? State.Stack.back().Indent + Style.IndentWidth
: FirstStartColumn;
@@ -1344,12 +1374,9 @@ unsigned ContinuationIndenter::reformatR
// - if the raw string prefix does not start on a newline, it is the current
// indent.
unsigned LastStartColumn = Current.NewlinesBefore
- ? FirstStartColumn - PrefixSize
+ ? FirstStartColumn - NewPrefixSize
: State.Stack.back().Indent;
- std::string RawText =
- Current.TokenText.substr(PrefixSize).drop_back(SuffixSize);
-
std::pair<tooling::Replacements, unsigned> Fixes = internal::reformat(
RawStringStyle, RawText, {tooling::Range(0, RawText.size())},
FirstStartColumn, NextStartColumn, LastStartColumn, "<stdin>",
@@ -1362,8 +1389,33 @@ unsigned ContinuationIndenter::reformatR
return 0;
}
if (!DryRun) {
+ if (NewDelimiter != OldDelimiter) {
+ // In 'R"delimiter(...', the delimiter starts 2 characters after the start
+ // of the token.
+ SourceLocation PrefixDelimiterStart =
+ Current.Tok.getLocation().getLocWithOffset(2);
+ auto PrefixErr = Whitespaces.addReplacement(tooling::Replacement(
+ SourceMgr, PrefixDelimiterStart, OldDelimiter.size(), NewDelimiter));
+ if (PrefixErr) {
+ llvm::errs()
+ << "Failed to update the prefix delimiter of a raw string: "
+ << llvm::toString(std::move(PrefixErr)) << "\n";
+ }
+ // In 'R"delimiter(...)delimiter"', the suffix delimiter starts at
+ // position length - 1 - |delimiter|.
+ SourceLocation SuffixDelimiterStart =
+ Current.Tok.getLocation().getLocWithOffset(Current.TokenText.size() -
+ 1 - OldDelimiter.size());
+ auto SuffixErr = Whitespaces.addReplacement(tooling::Replacement(
+ SourceMgr, SuffixDelimiterStart, OldDelimiter.size(), NewDelimiter));
+ if (SuffixErr) {
+ llvm::errs()
+ << "Failed to update the suffix delimiter of a raw string: "
+ << llvm::toString(std::move(SuffixErr)) << "\n";
+ }
+ }
SourceLocation OriginLoc =
- Current.Tok.getLocation().getLocWithOffset(PrefixSize);
+ Current.Tok.getLocation().getLocWithOffset(OldPrefixSize);
for (const tooling::Replacement &Fix : Fixes.first) {
auto Err = Whitespaces.addReplacement(tooling::Replacement(
SourceMgr, OriginLoc.getLocWithOffset(Fix.getOffset()),
@@ -1376,7 +1428,7 @@ unsigned ContinuationIndenter::reformatR
}
unsigned RawLastLineEndColumn = getLastLineEndColumn(
*NewCode, FirstStartColumn, Style.TabWidth, Encoding);
- State.Column = RawLastLineEndColumn + SuffixSize;
+ State.Column = RawLastLineEndColumn + NewSuffixSize;
return Fixes.second;
}
Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=322956&r1=322955&r2=322956&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Fri Jan 19 08:18:47 2018
@@ -459,6 +459,7 @@ template <> struct MappingTraits<FormatS
IO.mapOptional("Language", Format.Language);
IO.mapOptional("Delimiters", Format.Delimiters);
IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
+ IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
}
};
@@ -713,6 +714,7 @@ FormatStyle getGoogleStyle(FormatStyle::
"PARSE_TEXT_PROTO",
"ParseTextProto",
},
+ /*CanonicalDelimiter=*/"",
/*BasedOnStyle=*/"google",
}};
GoogleStyle.SpacesBeforeTrailingComments = 2;
Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=322956&r1=322955&r2=322956&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Fri Jan 19 08:18:47 2018
@@ -10429,13 +10429,15 @@ TEST_F(FormatTest, ParsesConfiguration)
FormatStyle::LK_TextProto,
{"pb", "proto"},
{"PARSE_TEXT_PROTO"},
+ /*CanonicalDelimiter=*/"",
"llvm",
},
{
FormatStyle::LK_Cpp,
{"cc", "cpp"},
{"C_CODEBLOCK", "CPPEVAL"},
- "",
+ /*CanonicalDelimiter=*/"cc",
+ /*BasedOnStyle=*/"",
},
};
@@ -10453,7 +10455,8 @@ TEST_F(FormatTest, ParsesConfiguration)
" - 'cpp'\n"
" EnclosingFunctions:\n"
" - 'C_CODEBLOCK'\n"
- " - 'CPPEVAL'\n",
+ " - 'CPPEVAL'\n"
+ " CanonicalDelimiter: 'cc'",
RawStringFormats, ExpectedRawStringFormats);
}
Modified: cfe/trunk/unittests/Format/FormatTestRawStrings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestRawStrings.cpp?rev=322956&r1=322955&r2=322956&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestRawStrings.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestRawStrings.cpp Fri Jan 19 08:18:47 2018
@@ -66,10 +66,13 @@ protected:
FormatStyle Style = getLLVMStyle();
Style.ColumnLimit = ColumnLimit;
Style.RawStringFormats = {
- {/*Language=*/FormatStyle::LK_TextProto,
- /*Delimiters=*/{"pb"},
- /*EnclosingFunctions=*/{},
- /*BasedOnStyle=*/"google"},
+ {
+ /*Language=*/FormatStyle::LK_TextProto,
+ /*Delimiters=*/{"pb"},
+ /*EnclosingFunctions=*/{},
+ /*CanonicalDelimiter=*/"",
+ /*BasedOnStyle=*/"google",
+ },
};
return Style;
}
@@ -77,9 +80,13 @@ protected:
FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) {
FormatStyle Style = getLLVMStyle();
Style.RawStringFormats = {
- {/*Language=*/FormatStyle::LK_Cpp,
- /*Delimiters=*/{"cpp"},
- /*EnclosingFunctions=*/{}, BasedOnStyle},
+ {
+ /*Language=*/FormatStyle::LK_Cpp,
+ /*Delimiters=*/{"cpp"},
+ /*EnclosingFunctions=*/{},
+ /*CanonicalDelimiter=*/"",
+ BasedOnStyle,
+ },
};
return Style;
}
@@ -87,9 +94,13 @@ protected:
FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
Style.RawStringFormats = {
- {/*Language=*/FormatStyle::LK_Cpp,
- /*Delimiters=*/{"cpp"},
- /*EnclosingFunctions=*/{}, BasedOnStyle},
+ {
+ /*Language=*/FormatStyle::LK_Cpp,
+ /*Delimiters=*/{"cpp"},
+ /*EnclosingFunctions=*/{},
+ /*CanonicalDelimiter=*/"",
+ BasedOnStyle,
+ },
};
return Style;
}
@@ -131,7 +142,13 @@ TEST_F(FormatTestRawStrings, UsesConfigu
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"},
+ {},
+ /*CanonicalDelimiter=*/"",
+ /*BasedOnStyle=*/"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));
}
@@ -752,6 +769,18 @@ a = ParseTextProto<ProtoType>(R"(key:val
Style));
}
+TEST_F(FormatTestRawStrings, UpdatesToCanonicalDelimiters) {
+ FormatStyle Style = getRawStringPbStyleWithColumns(25);
+ Style.RawStringFormats[0].CanonicalDelimiter = "proto";
+ expect_eq(R"test(a = R"proto(key: value)proto";)test",
+ format(R"test(a = R"pb(key:value)pb";)test", Style));
+
+ // Don't update to canonical delimiter if it occurs as a raw string suffix in
+ // the raw string content.
+ expect_eq(R"test(a = R"pb(key: ")proto")pb";)test",
+ format(R"test(a = R"pb(key:")proto")pb";)test", Style));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
More information about the cfe-commits
mailing list