r316903 - [clang-format] Format raw string literals
Galina Kistanova via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 30 17:38:12 PDT 2017
Hello Krasimir,
This commit broke one our builders:
http://lab.llvm.org:8011/builders/ubuntu-gcc7.1-werror/builds/2680
. . .
FAILED: /usr/local/gcc-7.1/bin/g++-7.1 -DGTEST_HAS_RTTI=0 -D_DEBUG
-D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
-D__STDC_LIMIT_MACROS -Itools/clang/lib/Format
-I/home/buildslave/am1i-slv2/ubuntu-gcc7.1-werror/llvm/tools/clang/lib/Format
-I/home/buildslave/am1i-slv2/ubuntu-gcc7.1-werror/llvm/tools/clang/include
-Itools/clang/include -Iinclude
-I/home/buildslave/am1i-slv2/ubuntu-gcc7.1-werror/llvm/include
-Wno-noexcept-type -fPIC -fvisibility-inlines-hidden -Werror
-Werror=date-time -std=c++11 -Wall -W -Wno-unused-parameter -Wwrite-strings
-Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long
-Wno-maybe-uninitialized -Wdelete-non-virtual-dtor -Wno-comment
-ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual
-fno-strict-aliasing -O3 -fPIC -UNDEBUG -fno-exceptions -fno-rtti -MD
-MT tools/clang/lib/Format/CMakeFiles/clangFormat.dir/Format.cpp.o -MF
tools/clang/lib/Format/CMakeFiles/clangFormat.dir/Format.cpp.o.d -o
tools/clang/lib/Format/CMakeFiles/clangFormat.dir/Format.cpp.o -c
/home/buildslave/am1i-slv2/ubuntu-gcc7.1-werror/llvm/tools/clang/lib/Format/Format.cpp
/home/buildslave/am1i-slv2/ubuntu-gcc7.1-werror/llvm/tools/clang/lib/Format/Format.cpp:48:74:
error: extra ‘;’ [-Werror=pedantic]
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory);
^
/home/buildslave/am1i-slv2/ubuntu-gcc7.1-werror/llvm/tools/clang/lib/Format/Format.cpp:49:74:
error: extra ‘;’ [-Werror=pedantic]
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat);
^
cc1plus: all warnings being treated as errors
Please have a look?
Thanks
Galina
On Mon, Oct 30, 2017 at 7:01 AM, Krasimir Georgiev via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: krasimir
> Date: Mon Oct 30 07:01:50 2017
> New Revision: 316903
>
> URL: http://llvm.org/viewvc/llvm-project?rev=316903&view=rev
> Log:
> [clang-format] Format raw string literals
>
> Summary:
> This patch adds raw string literal formatting.
>
> Reviewers: djasper, klimek
>
> Reviewed By: klimek
>
> Subscribers: klimek, mgorny
>
> Differential Revision: https://reviews.llvm.org/D35943
>
> Added:
> cfe/trunk/lib/Format/FormatInternal.h
> cfe/trunk/unittests/Format/FormatTestRawStrings.cpp
> Modified:
> cfe/trunk/include/clang/Format/Format.h
> cfe/trunk/lib/Format/ContinuationIndenter.cpp
> cfe/trunk/lib/Format/ContinuationIndenter.h
> cfe/trunk/lib/Format/Format.cpp
> cfe/trunk/lib/Format/FormatTokenLexer.cpp
> cfe/trunk/lib/Format/FormatTokenLexer.h
> cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp
> cfe/trunk/lib/Format/NamespaceEndCommentsFixer.h
> cfe/trunk/lib/Format/SortJavaScriptImports.cpp
> cfe/trunk/lib/Format/TokenAnalyzer.cpp
> cfe/trunk/lib/Format/TokenAnalyzer.h
> cfe/trunk/lib/Format/TokenAnnotator.cpp
> cfe/trunk/lib/Format/TokenAnnotator.h
> cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
> cfe/trunk/lib/Format/UnwrappedLineFormatter.h
> cfe/trunk/lib/Format/UnwrappedLineParser.cpp
> cfe/trunk/lib/Format/UnwrappedLineParser.h
> cfe/trunk/lib/Format/UsingDeclarationsSorter.cpp
> cfe/trunk/lib/Format/UsingDeclarationsSorter.h
> cfe/trunk/lib/Format/WhitespaceManager.cpp
> cfe/trunk/lib/Format/WhitespaceManager.h
> cfe/trunk/unittests/Format/CMakeLists.txt
> cfe/trunk/unittests/Format/FormatTest.cpp
>
> Modified: cfe/trunk/include/clang/Format/Format.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Format/Format.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Format/Format.h (original)
> +++ cfe/trunk/include/clang/Format/Format.h Mon Oct 30 07:01:50 2017
> @@ -1327,6 +1327,41 @@ struct FormatStyle {
> /// \brief Pointer and reference alignment style.
> PointerAlignmentStyle PointerAlignment;
>
> + /// See documentation of ``RawStringFormats``.
> + struct RawStringFormat {
> + /// \brief The delimiter that this raw string format matches.
> + std::string Delimiter;
> + /// \brief The language of this raw string.
> + LanguageKind Language;
> + /// \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 Delimiter == Other.Delimiter && Language == Other.Language &&
> + BasedOnStyle == Other.BasedOnStyle;
> + }
> + };
> +
> + /// \brief Raw string delimiters denoting that the raw string contents
> are
> + /// code in a particular language and can be reformatted.
> + ///
> + /// 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.
> + ///
> + /// To configure this in the .clang-format file, use:
> + /// \code{.yaml}
> + /// RawStringFormats:
> + /// - Delimiter: 'pb'
> + /// Language: TextProto
> + /// BasedOnStyle: llvm
> + /// - Delimiter: 'proto'
> + /// Language: TextProto
> + /// BasedOnStyle: google
> + /// \endcode
> + std::vector<RawStringFormat> RawStringFormats;
> +
> /// \brief If ``true``, clang-format will attempt to re-flow comments.
> /// \code
> /// false:
> @@ -1592,6 +1627,7 @@ struct FormatStyle {
> PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
> PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine
> &&
> PointerAlignment == R.PointerAlignment &&
> + RawStringFormats == R.RawStringFormats &&
> SpaceAfterCStyleCast == R.SpaceAfterCStyleCast &&
> SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword &&
> SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators
> &&
>
> Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> ContinuationIndenter.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
> +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Mon Oct 30 07:01:50 2017
> @@ -14,6 +14,7 @@
>
> #include "ContinuationIndenter.h"
> #include "BreakableToken.h"
> +#include "FormatInternal.h"
> #include "WhitespaceManager.h"
> #include "clang/Basic/OperatorPrecedence.h"
> #include "clang/Basic/SourceManager.h"
> @@ -76,6 +77,53 @@ static bool opensProtoMessageField(const
> (LessTok.Previous && LessTok.Previous->is(tok::equal))));
> }
>
> +// Returns the delimiter of a raw string literal, or None if TokenText is
> not
> +// the text of a raw string literal. The delimiter could be the empty
> string.
> +// For example, the delimiter of R"deli(cont)deli" is deli.
> +static llvm::Optional<StringRef> getRawStringDelimiter(StringRef
> TokenText) {
> + if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'.
> + || !TokenText.startswith("R\"") || !TokenText.endswith("\""))
> + return None;
> +
> + // A raw string starts with 'R"<delimiter>(' and delimiter is ascii and
> has
> + // size at most 16 by the standard, so the first '(' must be among the
> first
> + // 19 bytes.
> + size_t LParenPos = TokenText.substr(0, 19).find_first_of('(');
> + if (LParenPos == StringRef::npos)
> + return None;
> + StringRef Delimiter = TokenText.substr(2, LParenPos - 2);
> +
> + // Check that the string ends in ')Delimiter"'.
> + size_t RParenPos = TokenText.size() - Delimiter.size() - 2;
> + if (TokenText[RParenPos] != ')')
> + return None;
> + if (!TokenText.substr(RParenPos + 1).startswith(Delimiter))
> + return None;
> + return Delimiter;
> +}
> +
> +RawStringFormatStyleManager::RawStringFormatStyleManager(
> + const FormatStyle &CodeStyle) {
> + for (const auto &RawStringFormat : CodeStyle.RawStringFormats) {
> + FormatStyle Style;
> + if (!getPredefinedStyle(RawStringFormat.BasedOnStyle,
> + RawStringFormat.Language, &Style)) {
> + Style = getLLVMStyle();
> + Style.Language = RawStringFormat.Language;
> + }
> + Style.ColumnLimit = CodeStyle.ColumnLimit;
> + DelimiterStyle.insert({RawStringFormat.Delimiter, Style});
> + }
> +}
> +
> +llvm::Optional<FormatStyle>
> +RawStringFormatStyleManager::get(StringRef Delimiter) const {
> + auto It = DelimiterStyle.find(Delimiter);
> + if (It == DelimiterStyle.end())
> + return None;
> + return It->second;
> +}
> +
> ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
> const AdditionalKeywords
> &Keywords,
> const SourceManager &SourceMgr,
> @@ -85,14 +133,18 @@ ContinuationIndenter::ContinuationIndent
> : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr),
> Whitespaces(Whitespaces), Encoding(Encoding),
> BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
> - CommentPragmasRegex(Style.CommentPragmas) {}
> + CommentPragmasRegex(Style.CommentPragmas), RawStringFormats(Style)
> {}
>
> LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
> + unsigned FirstStartColumn,
> const AnnotatedLine *Line,
> bool DryRun) {
> LineState State;
> State.FirstIndent = FirstIndent;
> - State.Column = FirstIndent;
> + if (FirstStartColumn && Line->First->NewlinesBefore == 0)
> + State.Column = FirstStartColumn;
> + else
> + State.Column = FirstIndent;
> // With preprocessor directive indentation, the line starts on column 0
> // since it's indented after the hash, but FirstIndent is set to the
> // preprocessor indent.
> @@ -1216,6 +1268,89 @@ void ContinuationIndenter::moveStateToNe
> State.Stack.back().BreakBeforeParameter = true;
> }
>
> +static unsigned getLastLineEndColumn(StringRef Text, unsigned StartColumn,
> + unsigned TabWidth,
> + encoding::Encoding Encoding) {
> + size_t LastNewlinePos = Text.find_last_of("\n");
> + if (LastNewlinePos == StringRef::npos) {
> + return StartColumn +
> + encoding::columnWidthWithTabs(Text, StartColumn, TabWidth,
> Encoding);
> + } else {
> + return encoding::columnWidthWithTabs(Text.substr(LastNewlinePos),
> + /*StartColumn=*/0, TabWidth,
> Encoding);
> + }
> +}
> +
> +unsigned ContinuationIndenter::reformatRawStringLiteral(
> + const FormatToken &Current, unsigned StartColumn, LineState &State,
> + StringRef Delimiter, const FormatStyle &RawStringStyle, bool DryRun) {
> + // 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();
> +
> + // The first start column is the column the raw text starts.
> + unsigned FirstStartColumn = StartColumn + PrefixSize;
> +
> + // 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:
> + // - if the content starts on newline, it is one level more than the
> current
> + // indent, and
> + // - if the content does not start on a newline, it is the first start
> + // column.
> + // 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';
> + unsigned NextStartColumn = ContentStartsOnNewline
> + ? State.Stack.back().Indent +
> Style.IndentWidth
> + : FirstStartColumn;
> +
> + // The last start column is the column the raw string suffix starts if
> it is
> + // put on a newline.
> + // The last start column is the intended indentation of the raw string
> postfix
> + // if it is put on a newline. It is determined by the following rules:
> + // - if the raw string prefix starts on a newline, it is the column
> where
> + // that raw string prefix starts, and
> + // - if the raw string prefix does not start on a newline, it is the
> current
> + // indent.
> + unsigned LastStartColumn = Current.NewlinesBefore
> + ? FirstStartColumn - PrefixSize
> + : 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>",
> + /*FormattingAttemptStatus=*/nullptr);
> +
> + auto NewCode = applyAllReplacements(RawText, Fixes.first);
> + tooling::Replacements NoFixes;
> + if (!NewCode) {
> + State.Column += Current.ColumnWidth;
> + return 0;
> + }
> + if (!DryRun) {
> + SourceLocation OriginLoc =
> + Current.Tok.getLocation().getLocWithOffset(PrefixSize);
> + for (const tooling::Replacement &Fix : Fixes.first) {
> + auto Err = Whitespaces.addReplacement(tooling::Replacement(
> + SourceMgr, OriginLoc.getLocWithOffset(Fix.getOffset()),
> + Fix.getLength(), Fix.getReplacementText()));
> + if (Err) {
> + llvm::errs() << "Failed to reformat raw string: "
> + << llvm::toString(std::move(Err)) << "\n";
> + }
> + }
> + }
> + unsigned RawLastLineEndColumn = getLastLineEndColumn(
> + *NewCode, FirstStartColumn, Style.TabWidth, Encoding);
> + State.Column = RawLastLineEndColumn + SuffixSize;
> + return Fixes.second;
> +}
> +
> unsigned ContinuationIndenter::addMultilineToken(const FormatToken
> &Current,
> LineState &State) {
> if (!Current.IsMultiline)
> @@ -1238,9 +1373,18 @@ unsigned ContinuationIndenter::addMultil
> unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken
> &Current,
> LineState &State,
> bool DryRun) {
> - // Don't break multi-line tokens other than block comments. Instead,
> just
> - // update the state.
> - if (Current.isNot(TT_BlockComment) && Current.IsMultiline)
> + // Compute the raw string style to use in case this is a raw string
> literal
> + // that can be reformatted.
> + llvm::Optional<StringRef> Delimiter = None;
> + llvm::Optional<FormatStyle> RawStringStyle = None;
> + if (Current.isStringLiteral())
> + Delimiter = getRawStringDelimiter(Current.TokenText);
> + if (Delimiter)
> + RawStringStyle = RawStringFormats.get(*Delimiter);
> +
> + // Don't break multi-line tokens other than block comments and raw
> string
> + // literals. Instead, just update the state.
> + if (Current.isNot(TT_BlockComment) && !RawStringStyle &&
> Current.IsMultiline)
> return addMultilineToken(Current, State);
>
> // Don't break implicit string literals or import statements.
> @@ -1275,6 +1419,11 @@ unsigned ContinuationIndenter::breakProt
> if (Current.IsUnterminatedLiteral)
> return 0;
>
> + if (RawStringStyle) {
> + RawStringStyle->ColumnLimit = ColumnLimit;
> + return reformatRawStringLiteral(Current, StartColumn, State,
> *Delimiter,
> + *RawStringStyle, DryRun);
> + }
> StringRef Text = Current.TokenText;
> StringRef Prefix;
> StringRef Postfix;
>
> Modified: cfe/trunk/lib/Format/ContinuationIndenter.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> ContinuationIndenter.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/ContinuationIndenter.h (original)
> +++ cfe/trunk/lib/Format/ContinuationIndenter.h Mon Oct 30 07:01:50 2017
> @@ -20,6 +20,8 @@
> #include "FormatToken.h"
> #include "clang/Format/Format.h"
> #include "llvm/Support/Regex.h"
> +#include <map>
> +#include <tuple>
>
> namespace clang {
> class SourceManager;
> @@ -30,8 +32,17 @@ class AnnotatedLine;
> struct FormatToken;
> struct LineState;
> struct ParenState;
> +struct RawStringFormatStyleManager;
> class WhitespaceManager;
>
> +struct RawStringFormatStyleManager {
> + llvm::StringMap<FormatStyle> DelimiterStyle;
> +
> + RawStringFormatStyleManager(const FormatStyle &CodeStyle);
> +
> + llvm::Optional<FormatStyle> get(StringRef Delimiter) const;
> +};
> +
> class ContinuationIndenter {
> public:
> /// \brief Constructs a \c ContinuationIndenter to format \p Line
> starting in
> @@ -44,9 +55,11 @@ public:
> bool BinPackInconclusiveFunctions);
>
> /// \brief Get the initial state, i.e. the state after placing \p Line's
> - /// first token at \p FirstIndent.
> - LineState getInitialState(unsigned FirstIndent, const AnnotatedLine
> *Line,
> - bool DryRun);
> + /// first token at \p FirstIndent. When reformatting a fragment of
> code, as in
> + /// the case of formatting inside raw string literals, \p
> FirstStartColumn is
> + /// the column at which the state of the parent formatter is.
> + LineState getInitialState(unsigned FirstIndent, unsigned
> FirstStartColumn,
> + const AnnotatedLine *Line, bool DryRun);
>
> // FIXME: canBreak and mustBreak aren't strictly indentation-related.
> Find a
> // better home.
> @@ -88,15 +101,24 @@ private:
> /// \brief Update 'State' with the next token opening a nested block.
> void moveStateToNewBlock(LineState &State);
>
> + /// \brief Reformats a raw string literal.
> + ///
> + /// \returns An extra penalty induced by reformatting the token.
> + unsigned reformatRawStringLiteral(const FormatToken &Current,
> + unsigned StartColumn, LineState
> &State,
> + StringRef Delimiter,
> + const FormatStyle &RawStringStyle,
> + bool DryRun);
> +
> /// \brief If the current token sticks out over the end of the line,
> break
> /// it if possible.
> ///
> /// \returns An extra penalty if a token was broken, otherwise 0.
> ///
> - /// The returned penalty will cover the cost of the additional line
> breaks and
> - /// column limit violation in all lines except for the last one. The
> penalty
> - /// for the column limit violation in the last line (and in single line
> - /// tokens) is handled in \c addNextStateToQueue.
> + /// The returned penalty will cover the cost of the additional line
> breaks
> + /// and column limit violation in all lines except for the last one. The
> + /// penalty for the column limit violation in the last line (and in
> single
> + /// line tokens) is handled in \c addNextStateToQueue.
> unsigned breakProtrudingToken(const FormatToken &Current, LineState
> &State,
> bool DryRun);
>
> @@ -143,6 +165,7 @@ private:
> encoding::Encoding Encoding;
> bool BinPackInconclusiveFunctions;
> llvm::Regex CommentPragmasRegex;
> + const RawStringFormatStyleManager RawStringFormats;
> };
>
> struct ParenState {
>
> Modified: cfe/trunk/lib/Format/Format.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> Format.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/Format.cpp (original)
> +++ cfe/trunk/lib/Format/Format.cpp Mon Oct 30 07:01:50 2017
> @@ -16,6 +16,7 @@
> #include "clang/Format/Format.h"
> #include "AffectedRangeManager.h"
> #include "ContinuationIndenter.h"
> +#include "FormatInternal.h"
> #include "FormatTokenLexer.h"
> #include "NamespaceEndCommentsFixer.h"
> #include "SortJavaScriptImports.h"
> @@ -44,7 +45,8 @@
>
> using clang::format::FormatStyle;
>
> -LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
> +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::
> IncludeCategory);
> +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::
> RawStringFormat);
>
> namespace llvm {
> namespace yaml {
> @@ -389,6 +391,7 @@ template <> struct MappingTraits<FormatS
> IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
> Style.PenaltyReturnTypeOnItsOwnLine);
> IO.mapOptional("PointerAlignment", Style.PointerAlignment);
> + IO.mapOptional("RawStringFormats", Style.RawStringFormats);
> IO.mapOptional("ReflowComments", Style.ReflowComments);
> IO.mapOptional("SortIncludes", Style.SortIncludes);
> IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
> @@ -441,6 +444,14 @@ template <> struct MappingTraits<FormatS
> }
> };
>
> +template <> struct MappingTraits<FormatStyle::RawStringFormat> {
> + static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
> + IO.mapOptional("Delimiter", Format.Delimiter);
> + IO.mapOptional("Language", Format.Language);
> + IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
> + }
> +};
> +
> // 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.
> @@ -620,6 +631,7 @@ FormatStyle getLLVMStyle() {
> LLVMStyle.SpacesBeforeTrailingComments = 1;
> LLVMStyle.Standard = FormatStyle::LS_Cpp11;
> LLVMStyle.UseTab = FormatStyle::UT_Never;
> + LLVMStyle.RawStringFormats = {{"pb", FormatStyle::LK_TextProto,
> "google"}};
> LLVMStyle.ReflowComments = true;
> LLVMStyle.SpacesInParentheses = false;
> LLVMStyle.SpacesInSquareBrackets = false;
> @@ -895,7 +907,7 @@ public:
> JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
> : TokenAnalyzer(Env, Style) {}
>
> - tooling::Replacements
> + std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) override {
> @@ -903,7 +915,7 @@ public:
> AnnotatedLines.end());
> tooling::Replacements Result;
> requoteJSStringLiteral(AnnotatedLines, Result);
> - return Result;
> + return {Result, 0};
> }
>
> private:
> @@ -984,7 +996,7 @@ public:
> FormattingAttemptStatus *Status)
> : TokenAnalyzer(Env, Style), Status(Status) {}
>
> - tooling::Replacements
> + std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) override {
> @@ -1003,13 +1015,20 @@ public:
> ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
> Env.getSourceManager(), Whitespaces,
> Encoding,
> BinPackInconclusiveFunctions);
> - UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
> Tokens.getKeywords(),
> - Env.getSourceManager(), Status)
> - .format(AnnotatedLines);
> + unsigned Penalty =
> + UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
> + Tokens.getKeywords(),
> Env.getSourceManager(),
> + Status)
> + .format(AnnotatedLines, /*DryRun=*/false,
> + /*AdditionalIndent=*/0,
> + /*FixBadIndentation=*/false,
> + /*FirstStartColumn=*/Env.getFirstStartColumn(),
> + /*NextStartColumn=*/Env.getNextStartColumn(),
> + /*LastStartColumn=*/Env.getLastStartColumn());
> for (const auto &R : Whitespaces.generateReplacements())
> if (Result.add(R))
> - return Result;
> - return Result;
> + return {Result, 0};
> + return {Result, Penalty};
> }
>
> private:
> @@ -1097,7 +1116,7 @@ public:
> DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
>
> // FIXME: eliminate unused parameters.
> - tooling::Replacements
> + std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) override {
> @@ -1125,7 +1144,7 @@ public:
> }
> }
>
> - return generateFixes();
> + return {generateFixes(), 0};
> }
>
> private:
> @@ -1906,19 +1925,22 @@ cleanupAroundReplacements(StringRef Code
> return processReplacements(Cleanup, Code, NewReplaces, Style);
> }
>
> -tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
> - ArrayRef<tooling::Range> Ranges,
> - StringRef FileName,
> - FormattingAttemptStatus *Status) {
> +namespace internal {
> +std::pair<tooling::Replacements, unsigned>
> +reformat(const FormatStyle &Style, StringRef Code,
> + ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
> + unsigned NextStartColumn, unsigned LastStartColumn, StringRef
> FileName,
> + FormattingAttemptStatus *Status) {
> FormatStyle Expanded = expandPresets(Style);
> if (Expanded.DisableFormat)
> - return tooling::Replacements();
> + return {tooling::Replacements(), 0};
> if (isLikelyXml(Code))
> - return tooling::Replacements();
> + return {tooling::Replacements(), 0};
> if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
> - return tooling::Replacements();
> + return {tooling::Replacements(), 0};
>
> - typedef std::function<tooling::Replacements(const Environment &)>
> + typedef std::function<std::pair<tooling::Replacements, unsigned>(
> + const Environment &)>
> AnalyzerPass;
> SmallVector<AnalyzerPass, 4> Passes;
>
> @@ -1944,26 +1966,42 @@ tooling::Replacements reformat(const For
> return Formatter(Env, Expanded, Status).process();
> });
>
> - std::unique_ptr<Environment> Env =
> - Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
> + std::unique_ptr<Environment> Env = Environment::
> CreateVirtualEnvironment(
> + Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
> + LastStartColumn);
> llvm::Optional<std::string> CurrentCode = None;
> tooling::Replacements Fixes;
> + unsigned Penalty = 0;
> for (size_t I = 0, E = Passes.size(); I < E; ++I) {
> - tooling::Replacements PassFixes = Passes[I](*Env);
> + std::pair<tooling::Replacements, unsigned> PassFixes =
> Passes[I](*Env);
> auto NewCode = applyAllReplacements(
> - CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes);
> + CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
> if (NewCode) {
> - Fixes = Fixes.merge(PassFixes);
> + Fixes = Fixes.merge(PassFixes.first);
> + Penalty += PassFixes.second;
> if (I + 1 < E) {
> CurrentCode = std::move(*NewCode);
> Env = Environment::CreateVirtualEnvironment(
> *CurrentCode, FileName,
> - tooling::calculateRangesAfterReplacements(Fixes, Ranges));
> + tooling::calculateRangesAfterReplacements(Fixes, Ranges),
> + FirstStartColumn, NextStartColumn, LastStartColumn);
> }
> }
> }
>
> - return Fixes;
> + return {Fixes, Penalty};
> +}
> +} // namespace internal
> +
> +tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
> + ArrayRef<tooling::Range> Ranges,
> + StringRef FileName,
> + FormattingAttemptStatus *Status) {
> + return internal::reformat(Style, Code, Ranges,
> + /*FirstStartColumn=*/0,
> + /*NextStartColumn=*/0,
> + /*LastStartColumn=*/0, FileName, Status)
> + .first;
> }
>
> tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
> @@ -1975,7 +2013,7 @@ tooling::Replacements cleanup(const Form
> std::unique_ptr<Environment> Env =
> Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
> Cleaner Clean(*Env, Style);
> - return Clean.process();
> + return Clean.process().first;
> }
>
> tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
> @@ -1995,7 +2033,7 @@ tooling::Replacements fixNamespaceEndCom
> std::unique_ptr<Environment> Env =
> Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
> NamespaceEndCommentsFixer Fix(*Env, Style);
> - return Fix.process();
> + return Fix.process().first;
> }
>
> tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
> @@ -2005,7 +2043,7 @@ tooling::Replacements sortUsingDeclarati
> std::unique_ptr<Environment> Env =
> Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
> UsingDeclarationsSorter Sorter(*Env, Style);
> - return Sorter.process();
> + return Sorter.process().first;
> }
>
> LangOptions getFormattingLangOpts(const FormatStyle &Style) {
>
> Added: cfe/trunk/lib/Format/FormatInternal.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> FormatInternal.h?rev=316903&view=auto
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/FormatInternal.h (added)
> +++ cfe/trunk/lib/Format/FormatInternal.h Mon Oct 30 07:01:50 2017
> @@ -0,0 +1,79 @@
> +//===--- FormatInternal.h - Format C++ code ---------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +///
> +/// \file
> +/// \brief This file declares Format APIs to be used internally by the
> +/// formatting library implementation.
> +///
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
> +#define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
> +
> +namespace clang {
> +namespace format {
> +namespace internal {
> +
> +/// \brief Reformats the given \p Ranges in the code fragment \p Code.
> +///
> +/// A fragment of code could conceptually be surrounded by other code
> that might
> +/// constrain how that fragment is laid out.
> +/// For example, consider the fragment of code between 'R"(' and ')"',
> +/// exclusive, in the following code:
> +///
> +/// void outer(int x) {
> +/// string inner = R"(name: data
> +/// ^ FirstStartColumn
> +/// value: {
> +/// x: 1
> +/// ^ NextStartColumn
> +/// }
> +/// )";
> +/// ^ LastStartColumn
> +/// }
> +///
> +/// The outer code can influence the inner fragment as follows:
> +/// * \p FirstStartColumn specifies the column at which \p Code starts.
> +/// * \p NextStartColumn specifies the additional indent dictated by the
> +/// surrounding code. It is applied to the rest of the lines of \p
> Code.
> +/// * \p LastStartColumn specifies the column at which the last line of
> +/// \p Code should end, in case the last line is an empty line.
> +///
> +/// In the case where the last line of the fragment contains content,
> +/// the fragment ends at the end of that content and \p
> LastStartColumn is
> +/// not taken into account, for example in:
> +///
> +/// void block() {
> +/// string inner = R"(name: value)";
> +/// }
> +///
> +/// Each range is extended on either end to its next bigger logic unit,
> i.e.
> +/// everything that might influence its formatting or might be influenced
> by its
> +/// formatting.
> +///
> +/// Returns a pair P, where:
> +/// * P.first are the ``Replacements`` necessary to make all \p Ranges
> comply
> +/// with \p Style.
> +/// * P.second is the penalty induced by formatting the fragment \p
> Code.
> +/// If the formatting of the fragment doesn't have a notion of
> penalty,
> +/// returns 0.
> +///
> +/// If ``Status`` is non-null, its value will be populated with the
> status of
> +/// this formatting attempt. See \c FormattingAttemptStatus.
> +std::pair<tooling::Replacements, unsigned>
> +reformat(const FormatStyle &Style, StringRef Code,
> + ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
> + unsigned NextStartColumn, unsigned LastStartColumn, StringRef
> FileName,
> + FormattingAttemptStatus *Status);
> +
> +} // namespace internal
> +} // namespace format
> +} // namespace clang
> +
> +#endif
>
> Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> FormatTokenLexer.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original)
> +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Mon Oct 30 07:01:50 2017
> @@ -24,10 +24,10 @@ namespace clang {
> namespace format {
>
> FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr,
> FileID ID,
> - const FormatStyle &Style,
> + unsigned Column, const FormatStyle
> &Style,
> encoding::Encoding Encoding)
> : FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::
> NORMAL}),
> - Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
> + Column(Column), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
> Style(Style), IdentTable(getFormattingLangOpts(Style)),
> Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0),
> FormattingDisabled(false), MacroBlockBeginRegex(Style.
> MacroBlockBegin),
>
> Modified: cfe/trunk/lib/Format/FormatTokenLexer.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> FormatTokenLexer.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/FormatTokenLexer.h (original)
> +++ cfe/trunk/lib/Format/FormatTokenLexer.h Mon Oct 30 07:01:50 2017
> @@ -36,7 +36,7 @@ enum LexerState {
>
> class FormatTokenLexer {
> public:
> - FormatTokenLexer(const SourceManager &SourceMgr, FileID ID,
> + FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, unsigned
> Column,
> const FormatStyle &Style, encoding::Encoding Encoding);
>
> ArrayRef<FormatToken *> lex();
>
> Modified: cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> NamespaceEndCommentsFixer.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp (original)
> +++ cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp Mon Oct 30
> 07:01:50 2017
> @@ -137,7 +137,7 @@ NamespaceEndCommentsFixer::NamespaceEndC
> const FormatStyle
> &Style)
> : TokenAnalyzer(Env, Style) {}
>
> -tooling::Replacements NamespaceEndCommentsFixer::analyze(
> +std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::
> analyze(
> TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *>
> &AnnotatedLines,
> FormatTokenLexer &Tokens) {
> const SourceManager &SourceMgr = Env.getSourceManager();
> @@ -206,7 +206,7 @@ tooling::Replacements NamespaceEndCommen
> }
> StartLineIndex = SIZE_MAX;
> }
> - return Fixes;
> + return {Fixes, 0};
> }
>
> } // namespace format
>
> Modified: cfe/trunk/lib/Format/NamespaceEndCommentsFixer.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> NamespaceEndCommentsFixer.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/NamespaceEndCommentsFixer.h (original)
> +++ cfe/trunk/lib/Format/NamespaceEndCommentsFixer.h Mon Oct 30 07:01:50
> 2017
> @@ -25,7 +25,7 @@ class NamespaceEndCommentsFixer : public
> public:
> NamespaceEndCommentsFixer(const Environment &Env, const FormatStyle
> &Style);
>
> - tooling::Replacements
> + std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) override;
>
> Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> SortJavaScriptImports.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp (original)
> +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp Mon Oct 30 07:01:50
> 2017
> @@ -123,7 +123,7 @@ public:
> : TokenAnalyzer(Env, Style),
> FileContents(Env.getSourceManager().
> getBufferData(Env.getFileID())) {}
>
> - tooling::Replacements
> + std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) override {
> @@ -138,7 +138,7 @@ public:
> parseModuleReferences(Keywords, AnnotatedLines);
>
> if (References.empty())
> - return Result;
> + return {Result, 0};
>
> SmallVector<unsigned, 16> Indices;
> for (unsigned i = 0, e = References.size(); i != e; ++i)
> @@ -168,7 +168,7 @@ public:
> }
>
> if (ReferencesInOrder && SymbolsInOrder)
> - return Result;
> + return {Result, 0};
>
> SourceRange InsertionPoint = References[0].Range;
> InsertionPoint.setEnd(References[References.size() -
> 1].Range.getEnd());
> @@ -202,7 +202,7 @@ public:
> assert(false);
> }
>
> - return Result;
> + return {Result, 0};
> }
>
> private:
> @@ -449,7 +449,7 @@ tooling::Replacements sortJavaScriptImpo
> std::unique_ptr<Environment> Env =
> Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
> JavaScriptImportSorter Sorter(*Env, Style);
> - return Sorter.process();
> + return Sorter.process().first;
> }
>
> } // end namespace format
>
> Modified: cfe/trunk/lib/Format/TokenAnalyzer.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> TokenAnalyzer.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/TokenAnalyzer.cpp (original)
> +++ cfe/trunk/lib/Format/TokenAnalyzer.cpp Mon Oct 30 07:01:50 2017
> @@ -38,7 +38,10 @@ namespace format {
> // Code.
> std::unique_ptr<Environment>
> Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName,
> - ArrayRef<tooling::Range> Ranges) {
> + ArrayRef<tooling::Range> Ranges,
> + unsigned FirstStartColumn,
> + unsigned NextStartColumn,
> + unsigned LastStartColumn) {
> // This is referenced by `FileMgr` and will be released by `FileMgr`
> when it
> // is deleted.
> IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
> @@ -70,9 +73,9 @@ Environment::CreateVirtualEnvironment(St
> SourceLocation End = Start.getLocWithOffset(Range.getLength());
> CharRanges.push_back(CharSourceRange::getCharRange(Start, End));
> }
> - return llvm::make_unique<Environment>(ID, std::move(FileMgr),
> - std::move(VirtualSM),
> - std::move(Diagnostics),
> CharRanges);
> + return llvm::make_unique<Environment>(
> + ID, std::move(FileMgr), std::move(VirtualSM),
> std::move(Diagnostics),
> + CharRanges, FirstStartColumn, NextStartColumn, LastStartColumn);
> }
>
> TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle
> &Style)
> @@ -89,14 +92,16 @@ TokenAnalyzer::TokenAnalyzer(const Envir
> << "\n");
> }
>
> -tooling::Replacements TokenAnalyzer::process() {
> +std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() {
> tooling::Replacements Result;
> - FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(), Style,
> - Encoding);
> + FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(),
> + Env.getFirstStartColumn(), Style, Encoding);
>
> - UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(),
> *this);
> + UnwrappedLineParser Parser(Style, Tokens.getKeywords(),
> + Env.getFirstStartColumn(), Tokens.lex(),
> *this);
> Parser.parse();
> assert(UnwrappedLines.rbegin()->empty());
> + unsigned Penalty = 0;
> for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE;
> ++Run) {
> DEBUG(llvm::dbgs() << "Run " << Run << "...\n");
> SmallVector<AnnotatedLine *, 16> AnnotatedLines;
> @@ -107,13 +112,13 @@ tooling::Replacements TokenAnalyzer::pro
> Annotator.annotate(*AnnotatedLines.back());
> }
>
> - tooling::Replacements RunResult =
> + std::pair<tooling::Replacements, unsigned> RunResult =
> analyze(Annotator, AnnotatedLines, Tokens);
>
> DEBUG({
> llvm::dbgs() << "Replacements for run " << Run << ":\n";
> - for (tooling::Replacements::const_iterator I = RunResult.begin(),
> - E = RunResult.end();
> + for (tooling::Replacements::const_iterator I =
> RunResult.first.begin(),
> + E =
> RunResult.first.end();
> I != E; ++I) {
> llvm::dbgs() << I->toString() << "\n";
> }
> @@ -121,17 +126,19 @@ tooling::Replacements TokenAnalyzer::pro
> for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
> delete AnnotatedLines[i];
> }
> - for (const auto &R : RunResult) {
> +
> + Penalty += RunResult.second;
> + for (const auto &R : RunResult.first) {
> auto Err = Result.add(R);
> // FIXME: better error handling here. For now, simply return an
> empty
> // Replacements to indicate failure.
> if (Err) {
> llvm::errs() << llvm::toString(std::move(Err)) << "\n";
> - return tooling::Replacements();
> + return {tooling::Replacements(), 0};
> }
> }
> }
> - return Result;
> + return {Result, Penalty};
> }
>
> void TokenAnalyzer::consumeUnwrappedLine(const UnwrappedLine &TheLine) {
>
> Modified: cfe/trunk/lib/Format/TokenAnalyzer.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> TokenAnalyzer.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/TokenAnalyzer.h (original)
> +++ cfe/trunk/lib/Format/TokenAnalyzer.h Mon Oct 30 07:01:50 2017
> @@ -37,21 +37,37 @@ namespace format {
> class Environment {
> public:
> Environment(SourceManager &SM, FileID ID, ArrayRef<CharSourceRange>
> Ranges)
> - : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM) {}
> + : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM),
> + FirstStartColumn(0),
> + NextStartColumn(0),
> + LastStartColumn(0) {}
>
> Environment(FileID ID, std::unique_ptr<FileManager> FileMgr,
> std::unique_ptr<SourceManager> VirtualSM,
> std::unique_ptr<DiagnosticsEngine> Diagnostics,
> - const std::vector<CharSourceRange> &CharRanges)
> + const std::vector<CharSourceRange> &CharRanges,
> + unsigned FirstStartColumn,
> + unsigned NextStartColumn,
> + unsigned LastStartColumn)
> : ID(ID), CharRanges(CharRanges.begin(), CharRanges.end()),
> - SM(*VirtualSM), FileMgr(std::move(FileMgr)),
> + SM(*VirtualSM),
> + FirstStartColumn(FirstStartColumn),
> + NextStartColumn(NextStartColumn),
> + LastStartColumn(LastStartColumn),
> + FileMgr(std::move(FileMgr)),
> VirtualSM(std::move(VirtualSM)), Diagnostics(std::move(Diagnostics))
> {}
>
> - // This sets up an virtual file system with file \p FileName containing
> \p
> - // Code.
> + // This sets up an virtual file system with file \p FileName containing
> the
> + // fragment \p Code. Assumes that \p Code starts at \p FirstStartColumn,
> + // that the next lines of \p Code should start at \p NextStartColumn,
> and
> + // that \p Code should end at \p LastStartColumn if it ends in newline.
> + // See also the documentation of clang::format::internal::reformat.
> static std::unique_ptr<Environment>
> CreateVirtualEnvironment(StringRef Code, StringRef FileName,
> - ArrayRef<tooling::Range> Ranges);
> + ArrayRef<tooling::Range> Ranges,
> + unsigned FirstStartColumn = 0,
> + unsigned NextStartColumn = 0,
> + unsigned LastStartColumn = 0);
>
> FileID getFileID() const { return ID; }
>
> @@ -59,10 +75,25 @@ public:
>
> const SourceManager &getSourceManager() const { return SM; }
>
> + // Returns the column at which the fragment of code managed by this
> + // environment starts.
> + unsigned getFirstStartColumn() const { return FirstStartColumn; }
> +
> + // Returns the column at which subsequent lines of the fragment of code
> + // managed by this environment should start.
> + unsigned getNextStartColumn() const { return NextStartColumn; }
> +
> + // Returns the column at which the fragment of code managed by this
> + // environment should end if it ends in a newline.
> + unsigned getLastStartColumn() const { return LastStartColumn; }
> +
> private:
> FileID ID;
> SmallVector<CharSourceRange, 8> CharRanges;
> SourceManager &SM;
> + unsigned FirstStartColumn;
> + unsigned NextStartColumn;
> + unsigned LastStartColumn;
>
> // The order of these fields are important - they should be in the same
> order
> // as they are created in `CreateVirtualEnvironment` so that they can be
> @@ -76,10 +107,10 @@ class TokenAnalyzer : public UnwrappedLi
> public:
> TokenAnalyzer(const Environment &Env, const FormatStyle &Style);
>
> - tooling::Replacements process();
> + std::pair<tooling::Replacements, unsigned> process();
>
> protected:
> - virtual tooling::Replacements
> + virtual std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) = 0;
>
> Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> TokenAnnotator.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
> +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Oct 30 07:01:50 2017
> @@ -1891,7 +1891,8 @@ void TokenAnnotator::calculateFormatting
> }
>
> Line.First->TotalLength =
> - Line.First->IsMultiline ? Style.ColumnLimit :
> Line.First->ColumnWidth;
> + Line.First->IsMultiline ? Style.ColumnLimit
> + : Line.FirstStartColumn +
> Line.First->ColumnWidth;
> FormatToken *Current = Line.First->Next;
> bool InFunctionDecl = Line.MightBeFunctionDecl;
> while (Current) {
>
> Modified: cfe/trunk/lib/Format/TokenAnnotator.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> TokenAnnotator.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/TokenAnnotator.h (original)
> +++ cfe/trunk/lib/Format/TokenAnnotator.h Mon Oct 30 07:01:50 2017
> @@ -43,7 +43,8 @@ public:
> InPPDirective(Line.InPPDirective),
> MustBeDeclaration(Line.MustBeDeclaration),
> MightBeFunctionDecl(false),
> IsMultiVariableDeclStmt(false), Affected(false),
> - LeadingEmptyLinesAffected(false), ChildrenAffected(false) {
> + LeadingEmptyLinesAffected(false), ChildrenAffected(false),
> + FirstStartColumn(Line.FirstStartColumn) {
> assert(!Line.Tokens.empty());
>
> // Calculate Next and Previous for all tokens. Note that we must
> overwrite
> @@ -127,6 +128,8 @@ public:
> /// \c True if one of this line's children intersects with an input
> range.
> bool ChildrenAffected;
>
> + unsigned FirstStartColumn;
> +
> private:
> // Disallow copying.
> AnnotatedLine(const AnnotatedLine &) = delete;
>
> Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> UnwrappedLineFormatter.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (original)
> +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Mon Oct 30 07:01:50
> 2017
> @@ -659,7 +659,9 @@ public:
> /// \brief Formats an \c AnnotatedLine and returns the penalty.
> ///
> /// If \p DryRun is \c false, directly applies the changes.
> - virtual unsigned formatLine(const AnnotatedLine &Line, unsigned
> FirstIndent,
> + virtual unsigned formatLine(const AnnotatedLine &Line,
> + unsigned FirstIndent,
> + unsigned FirstStartColumn,
> bool DryRun) = 0;
>
> protected:
> @@ -730,7 +732,8 @@ protected:
> *Child->First, /*Newlines=*/0, /*Spaces=*/1,
> /*StartOfTokenColumn=*/State.Column,
> State.Line->InPPDirective);
> }
> - Penalty += formatLine(*Child, State.Column + 1, DryRun);
> + Penalty +=
> + formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0,
> DryRun);
>
> State.Column += 1 + Child->Last->TotalLength;
> return true;
> @@ -756,10 +759,10 @@ public:
> /// \brief Formats the line, simply keeping all of the input's line
> breaking
> /// decisions.
> unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
> - bool DryRun) override {
> + unsigned FirstStartColumn, bool DryRun) override {
> assert(!DryRun);
> - LineState State =
> - Indenter->getInitialState(FirstIndent, &Line, /*DryRun=*/false);
> + LineState State = Indenter->getInitialState(FirstIndent,
> FirstStartColumn,
> + &Line, /*DryRun=*/false);
> while (State.NextToken) {
> bool Newline =
> Indenter->mustBreak(State) ||
> @@ -782,9 +785,10 @@ public:
>
> /// \brief Puts all tokens into a single line.
> unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
> - bool DryRun) override {
> + unsigned FirstStartColumn, bool DryRun) override {
> unsigned Penalty = 0;
> - LineState State = Indenter->getInitialState(FirstIndent, &Line,
> DryRun);
> + LineState State =
> + Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line,
> DryRun);
> while (State.NextToken) {
> formatChildren(State, /*Newline=*/false, DryRun, Penalty);
> Indenter->addTokenToState(
> @@ -806,8 +810,9 @@ public:
> /// \brief Formats the line by finding the best line breaks with line
> lengths
> /// below the column limit.
> unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
> - bool DryRun) override {
> - LineState State = Indenter->getInitialState(FirstIndent, &Line,
> DryRun);
> + unsigned FirstStartColumn, bool DryRun) override {
> + LineState State =
> + Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line,
> DryRun);
>
> // If the ObjC method declaration does not fit on a line, we should
> format
> // it with one arg per line.
> @@ -974,7 +979,10 @@ private:
> unsigned
> UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *>
> &Lines,
> bool DryRun, int AdditionalIndent,
> - bool FixBadIndentation) {
> + bool FixBadIndentation,
> + unsigned FirstStartColumn,
> + unsigned NextStartColumn,
> + unsigned LastStartColumn) {
> LineJoiner Joiner(Style, Keywords, Lines);
>
> // Try to look up already computed penalty in DryRun-mode.
> @@ -994,9 +1002,10 @@ UnwrappedLineFormatter::format(const Sma
> // The minimum level of consecutive lines that have been formatted.
> unsigned RangeMinLevel = UINT_MAX;
>
> + bool FirstLine = true;
> for (const AnnotatedLine *Line =
> Joiner.getNextMergedLine(DryRun, IndentTracker);
> - Line; Line = NextLine) {
> + Line; Line = NextLine, FirstLine = false) {
> const AnnotatedLine &TheLine = *Line;
> unsigned Indent = IndentTracker.getIndent();
>
> @@ -1020,8 +1029,12 @@ UnwrappedLineFormatter::format(const Sma
> }
>
> if (ShouldFormat && TheLine.Type != LT_Invalid) {
> - if (!DryRun)
> - formatFirstToken(TheLine, PreviousLine, Indent);
> + if (!DryRun) {
> + bool LastLine = Line->First->is(tok::eof);
> + formatFirstToken(TheLine, PreviousLine,
> + Indent,
> + LastLine ? LastStartColumn : NextStartColumn +
> Indent);
> + }
>
> NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
> unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective,
> NextLine);
> @@ -1030,16 +1043,18 @@ UnwrappedLineFormatter::format(const Sma
> (TheLine.Type == LT_ImportStatement &&
> (Style.Language != FormatStyle::LK_JavaScript ||
> !Style.JavaScriptWrapImports));
> -
> if (Style.ColumnLimit == 0)
> NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
> - .formatLine(TheLine, Indent, DryRun);
> + .formatLine(TheLine, NextStartColumn + Indent,
> + FirstLine ? FirstStartColumn : 0, DryRun);
> else if (FitsIntoOneLine)
> Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style,
> this)
> - .formatLine(TheLine, Indent, DryRun);
> + .formatLine(TheLine, NextStartColumn + Indent,
> + FirstLine ? FirstStartColumn : 0,
> DryRun);
> else
> Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style,
> this)
> - .formatLine(TheLine, Indent, DryRun);
> + .formatLine(TheLine, NextStartColumn + Indent,
> + FirstLine ? FirstStartColumn : 0,
> DryRun);
> RangeMinLevel = std::min(RangeMinLevel, TheLine.Level);
> } else {
> // If no token in the current line is affected, we still need to
> format
> @@ -1062,6 +1077,7 @@ UnwrappedLineFormatter::format(const Sma
> // Format the first token.
> if (ReformatLeadingWhitespace)
> formatFirstToken(TheLine, PreviousLine,
> + TheLine.First->OriginalColumn,
> TheLine.First->OriginalColumn);
> else
> Whitespaces->addUntouchableToken(*TheLine.First,
> @@ -1084,12 +1100,14 @@ UnwrappedLineFormatter::format(const Sma
>
> void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
> const AnnotatedLine
> *PreviousLine,
> - unsigned Indent) {
> + unsigned Indent,
> + unsigned NewlineIndent) {
> FormatToken &RootToken = *Line.First;
> if (RootToken.is(tok::eof)) {
> unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
> - Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0,
> - /*StartOfTokenColumn=*/0);
> + unsigned TokenIndent = Newlines ? NewlineIndent : 0;
> + Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
> + TokenIndent);
> return;
> }
> unsigned Newlines =
> @@ -1104,10 +1122,6 @@ void UnwrappedLineFormatter::formatFirst
> if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
> Newlines = 0;
>
> - // Preprocessor directives get indented after the hash, if indented.
> - if (Line.Type == LT_PreprocessorDirective || Line.Type ==
> LT_ImportStatement)
> - Indent = 0;
> -
> // Remove empty lines after "{".
> if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
> PreviousLine->Last->is(tok::l_brace) &&
> @@ -1125,6 +1139,13 @@ void UnwrappedLineFormatter::formatFirst
> (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
> Newlines = std::min(1u, Newlines);
>
> + if (Newlines)
> + Indent = NewlineIndent;
> +
> + // Preprocessor directives get indented after the hash, if indented.
> + if (Line.Type == LT_PreprocessorDirective || Line.Type ==
> LT_ImportStatement)
> + Indent = 0;
> +
> Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
> Line.InPPDirective &&
> !RootToken.HasUnescapedNewline);
>
> Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> UnwrappedLineFormatter.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/UnwrappedLineFormatter.h (original)
> +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.h Mon Oct 30 07:01:50 2017
> @@ -40,13 +40,17 @@ public:
> /// \brief Format the current block and return the penalty.
> unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines,
> bool DryRun = false, int AdditionalIndent = 0,
> - bool FixBadIndentation = false);
> + bool FixBadIndentation = false,
> + unsigned FirstStartColumn = 0,
> + unsigned NextStartColumn = 0,
> + unsigned LastStartColumn = 0);
>
> private:
> /// \brief Add a new line and the required indent before the first Token
> /// of the \c UnwrappedLine if there was no structural parsing error.
> void formatFirstToken(const AnnotatedLine &Line,
> - const AnnotatedLine *PreviousLine, unsigned
> Indent);
> + const AnnotatedLine *PreviousLine, unsigned
> Indent,
> + unsigned NewlineIndent);
>
> /// \brief Returns the column limit for a line, taking into account
> whether we
> /// need an escaped newline due to a continued preprocessor directive.
>
> Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> UnwrappedLineParser.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original)
> +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Mon Oct 30 07:01:50 2017
> @@ -225,6 +225,7 @@ private:
>
> UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
> const AdditionalKeywords
> &Keywords,
> + unsigned FirstStartColumn,
> ArrayRef<FormatToken *> Tokens,
> UnwrappedLineConsumer &Callback)
> : Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
> @@ -232,7 +233,7 @@ UnwrappedLineParser::UnwrappedLineParser
> CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
> Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
> IfNdefCondition(nullptr), FoundIncludeGuardStart(false),
> - IncludeGuardRejected(false) {}
> + IncludeGuardRejected(false), FirstStartColumn(FirstStartColumn) {}
>
> void UnwrappedLineParser::reset() {
> PPBranchLevel = -1;
> @@ -247,10 +248,12 @@ void UnwrappedLineParser::reset() {
> CurrentLines = &Lines;
> DeclarationScopeStack.clear();
> PPStack.clear();
> + Line->FirstStartColumn = FirstStartColumn;
> }
>
> void UnwrappedLineParser::parse() {
> IndexedTokenSource TokenSource(AllTokens);
> + Line->FirstStartColumn = FirstStartColumn;
> do {
> DEBUG(llvm::dbgs() << "----\n");
> reset();
> @@ -2193,7 +2196,8 @@ void UnwrappedLineParser::parseJavaScrip
>
> LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine
> &Line,
> StringRef Prefix = "") {
> - llvm::dbgs() << Prefix << "Line(" << Line.Level << ")"
> + llvm::dbgs() << Prefix << "Line(" << Line.Level
> + << ", FSC=" << Line.FirstStartColumn << ")"
> << (Line.InPPDirective ? " MACRO" : "") << ": ";
> for (std::list<UnwrappedLineNode>::const_iterator I =
> Line.Tokens.begin(),
> E = Line.Tokens.end();
> @@ -2226,6 +2230,7 @@ void UnwrappedLineParser::addUnwrappedLi
> CurrentLines->push_back(std::move(*Line));
> Line->Tokens.clear();
> Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
> + Line->FirstStartColumn = 0;
> if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
> CurrentLines->append(
> std::make_move_iterator(PreprocessorDirectives.begin()),
>
> Modified: cfe/trunk/lib/Format/UnwrappedLineParser.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> UnwrappedLineParser.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/UnwrappedLineParser.h (original)
> +++ cfe/trunk/lib/Format/UnwrappedLineParser.h Mon Oct 30 07:01:50 2017
> @@ -56,6 +56,8 @@ struct UnwrappedLine {
> size_t MatchingOpeningBlockLineIndex;
>
> static const size_t kInvalidIndex = -1;
> +
> + unsigned FirstStartColumn = 0;
> };
>
> class UnwrappedLineConsumer {
> @@ -71,6 +73,7 @@ class UnwrappedLineParser {
> public:
> UnwrappedLineParser(const FormatStyle &Style,
> const AdditionalKeywords &Keywords,
> + unsigned FirstStartColumn,
> ArrayRef<FormatToken *> Tokens,
> UnwrappedLineConsumer &Callback);
>
> @@ -249,6 +252,10 @@ private:
> FormatToken *IfNdefCondition;
> bool FoundIncludeGuardStart;
> bool IncludeGuardRejected;
> + // Contains the first start column where the source begins. This is
> zero for
> + // normal source code and may be nonzero when formatting a code
> fragment that
> + // does not start at the beginning of the file.
> + unsigned FirstStartColumn;
>
> friend class ScopedLineState;
> friend class CompoundStatementIndenter;
>
> Modified: cfe/trunk/lib/Format/UsingDeclarationsSorter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> UsingDeclarationsSorter.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/UsingDeclarationsSorter.cpp (original)
> +++ cfe/trunk/lib/Format/UsingDeclarationsSorter.cpp Mon Oct 30 07:01:50
> 2017
> @@ -124,7 +124,7 @@ UsingDeclarationsSorter::UsingDeclaratio
> const FormatStyle &Style)
> : TokenAnalyzer(Env, Style) {}
>
> -tooling::Replacements UsingDeclarationsSorter::analyze(
> +std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::
> analyze(
> TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *>
> &AnnotatedLines,
> FormatTokenLexer &Tokens) {
> const SourceManager &SourceMgr = Env.getSourceManager();
> @@ -149,7 +149,7 @@ tooling::Replacements UsingDeclarationsS
> UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I],
> Label));
> }
> endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
> - return Fixes;
> + return {Fixes, 0};
> }
>
> } // namespace format
>
> Modified: cfe/trunk/lib/Format/UsingDeclarationsSorter.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> UsingDeclarationsSorter.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/UsingDeclarationsSorter.h (original)
> +++ cfe/trunk/lib/Format/UsingDeclarationsSorter.h Mon Oct 30 07:01:50
> 2017
> @@ -25,7 +25,7 @@ class UsingDeclarationsSorter : public T
> public:
> UsingDeclarationsSorter(const Environment &Env, const FormatStyle
> &Style);
>
> - tooling::Replacements
> + std::pair<tooling::Replacements, unsigned>
> analyze(TokenAnnotator &Annotator,
> SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
> FormatTokenLexer &Tokens) override;
>
> Modified: cfe/trunk/lib/Format/WhitespaceManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> WhitespaceManager.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/WhitespaceManager.cpp (original)
> +++ cfe/trunk/lib/Format/WhitespaceManager.cpp Mon Oct 30 07:01:50 2017
> @@ -67,6 +67,11 @@ void WhitespaceManager::addUntouchableTo
> /*IsInsideToken=*/false));
> }
>
> +llvm::Error
> +WhitespaceManager::addReplacement(const tooling::Replacement
> &Replacement) {
> + return Replaces.add(Replacement);
> +}
> +
> void WhitespaceManager::replaceWhitespaceInToken(
> const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
> StringRef PreviousPostfix, StringRef CurrentPrefix, bool
> InPPDirective,
>
> Modified: cfe/trunk/lib/Format/WhitespaceManager.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/
> WhitespaceManager.h?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Format/WhitespaceManager.h (original)
> +++ cfe/trunk/lib/Format/WhitespaceManager.h Mon Oct 30 07:01:50 2017
> @@ -57,6 +57,8 @@ public:
> /// was not called.
> void addUntouchableToken(const FormatToken &Tok, bool InPPDirective);
>
> + llvm::Error addReplacement(const tooling::Replacement &Replacement);
> +
> /// \brief Inserts or replaces whitespace in the middle of a token.
> ///
> /// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p
> CurrentPrefix
>
> Modified: cfe/trunk/unittests/Format/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> Format/CMakeLists.txt?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/unittests/Format/CMakeLists.txt (original)
> +++ cfe/trunk/unittests/Format/CMakeLists.txt Mon Oct 30 07:01:50 2017
> @@ -10,6 +10,7 @@ add_clang_unittest(FormatTests
> FormatTestJava.cpp
> FormatTestObjC.cpp
> FormatTestProto.cpp
> + FormatTestRawStrings.cpp
> FormatTestSelective.cpp
> FormatTestTextProto.cpp
> NamespaceEndCommentsFixerTest.cpp
>
> Modified: cfe/trunk/unittests/Format/FormatTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> Format/FormatTest.cpp?rev=316903&r1=316902&r2=316903&view=diff
> ============================================================
> ==================
> --- cfe/trunk/unittests/Format/FormatTest.cpp (original)
> +++ cfe/trunk/unittests/Format/FormatTest.cpp Mon Oct 30 07:01:50 2017
> @@ -10254,6 +10254,20 @@ TEST_F(FormatTest, ParsesConfiguration)
> " Priority: 1",
> IncludeCategories, ExpectedCategories);
> CHECK_PARSE("IncludeIsMainRegex: 'abc$'", IncludeIsMainRegex, "abc$");
> +
> + Style.RawStringFormats.clear();
> + std::vector<FormatStyle::RawStringFormat> ExpectedRawStringFormats = {
> + {"pb", FormatStyle::LK_TextProto, "llvm"},
> + {"cpp", FormatStyle::LK_Cpp, "google"}};
> +
> + CHECK_PARSE("RawStringFormats:\n"
> + " - Delimiter: 'pb'\n"
> + " Language: TextProto\n"
> + " BasedOnStyle: llvm\n"
> + " - Delimiter: 'cpp'\n"
> + " Language: Cpp\n"
> + " BasedOnStyle: google",
> + RawStringFormats, ExpectedRawStringFormats);
> }
>
> TEST_F(FormatTest, ParsesConfigurationWithLanguages) {
>
> Added: cfe/trunk/unittests/Format/FormatTestRawStrings.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/
> Format/FormatTestRawStrings.cpp?rev=316903&view=auto
> ============================================================
> ==================
> --- cfe/trunk/unittests/Format/FormatTestRawStrings.cpp (added)
> +++ cfe/trunk/unittests/Format/FormatTestRawStrings.cpp Mon Oct 30
> 07:01:50 2017
> @@ -0,0 +1,733 @@
> +//===- unittest/Format/FormatTestRawStrings.cpp - Formatting unit tests
> ---===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "clang/Format/Format.h"
> +
> +#include "../Tooling/ReplacementTest.h"
> +#include "FormatTestUtils.h"
> +
> +#include "clang/Frontend/TextDiagnosticPrinter.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "gtest/gtest.h"
> +
> +#define DEBUG_TYPE "format-test"
> +
> +using clang::tooling::ReplacementTest;
> +using clang::tooling::toReplacements;
> +
> +namespace clang {
> +namespace format {
> +namespace {
> +
> +class FormatTestRawStrings : public ::testing::Test {
> +protected:
> + enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete,
> SC_DoNotCheck };
> +
> + std::string format(llvm::StringRef Code,
> + const FormatStyle &Style = getLLVMStyle(),
> + StatusCheck CheckComplete = SC_ExpectComplete) {
> + DEBUG(llvm::errs() << "---\n");
> + DEBUG(llvm::errs() << Code << "\n\n");
> + std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
> + FormattingAttemptStatus Status;
> + tooling::Replacements Replaces =
> + reformat(Style, Code, Ranges, "<stdin>", &Status);
> + if (CheckComplete != SC_DoNotCheck) {
> + bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
> + EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
> + << Code << "\n\n";
> + }
> + ReplacementCount = Replaces.size();
> + auto Result = applyAllReplacements(Code, Replaces);
> + EXPECT_TRUE(static_cast<bool>(Result));
> + DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
> + return *Result;
> + }
> +
> + FormatStyle getStyleWithColumns(FormatStyle Style, unsigned
> ColumnLimit) {
> + Style.ColumnLimit = ColumnLimit;
> + return Style;
> + }
> +
> + FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
> + return getStyleWithColumns(getLLVMStyle(), ColumnLimit);
> + }
> +
> + int ReplacementCount;
> +
> + FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) {
> + FormatStyle Style = getLLVMStyle();
> + Style.ColumnLimit = ColumnLimit;
> + Style.RawStringFormats = {{/*Delimiter=*/"pb",
> + /*Kind=*/FormatStyle::LK_TextProto,
> + /*BasedOnStyle=*/"google"}};
> + return Style;
> + }
> +
> + FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) {
> + FormatStyle Style = getLLVMStyle();
> + Style.RawStringFormats = {{/*Delimiter=*/"cpp",
> + /*Kind=*/FormatStyle::LK_Cpp,
> BasedOnStyle}};
> + return Style;
> + }
> +
> + FormatStyle getRawStringGoogleCppStyleBasedOn(std::string
> BasedOnStyle) {
> + FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
> + Style.RawStringFormats = {{/*Delimiter=*/"cpp",
> + /*Kind=*/FormatStyle::LK_Cpp,
> BasedOnStyle}};
> + return Style;
> + }
> +
> + // Gcc 4.8 doesn't support raw string literals in macros, which breaks
> some
> + // build bots. We use this function instead.
> + void expect_eq(const std::string Expected, const std::string Actual) {
> + EXPECT_EQ(Expected, Actual);
> + }
> +};
> +
> +TEST_F(FormatTestRawStrings, ReformatsAccordingToBaseStyle) {
> + // llvm style puts '*' on the right.
> + // google style puts '*' on the left.
> +
> + // Use the llvm style if the raw string style has no BasedOnStyle.
> + expect_eq(R"test(int *i = R"cpp(int *p = nullptr;)cpp")test",
> + format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
> + getRawStringLLVMCppStyleBasedOn("")));
> +
> + // Use the google style if the raw string style has BasedOnStyle=google.
> + expect_eq(R"test(int *i = R"cpp(int* p = nullptr;)cpp")test",
> + format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
> + getRawStringLLVMCppStyleBasedOn("google")));
> +
> + // Use the llvm style if the raw string style has no BasedOnStyle=llvm.
> + expect_eq(R"test(int* i = R"cpp(int *p = nullptr;)cpp")test",
> + format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
> + getRawStringGoogleCppStyleBasedOn("llvm")));
> +}
> +
> +TEST_F(FormatTestRawStrings, MatchesDelimitersCaseSensitively) {
> + // Don't touch the 'PB' raw string, format the 'pb' raw string.
> + expect_eq(R"test(
> +s = R"PB(item:1)PB";
> +t = R"pb(item: 1)pb";)test",
> + format(R"test(
> +s = R"PB(item:1)PB";
> +t = R"pb(item:1)pb";)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + FormatStyle MixedStyle = getLLVMStyle();
> + MixedStyle.RawStringFormats = {
> + {/*Delimiter=*/"cpp", /*Kind=*/FormatStyle::LK_Cpp,
> + /*BasedOnStyle=*/"llvm"},
> + {/*Delimiter=*/"CPP", /*Kind=*/FormatStyle::LK_Cpp,
> + /*BasedOnStyle=*/"google"}};
> +
> + // Format the 'cpp' raw string with '*' on the right.
> + // Format the 'CPP' raw string with '*' on the left.
> + // Do not format the 'Cpp' raw string.
> + // Do not format non-raw strings.
> + expect_eq(R"test(
> +a = R"cpp(int *i = 0;)cpp";
> +b = R"CPP(int* j = 0;)CPP";
> +c = R"Cpp(int * k = 0;)Cpp";
> +d = R"cpp(int * k = 0;)Cpp";)test",
> + format(R"test(
> +a = R"cpp(int * i = 0;)cpp";
> +b = R"CPP(int * j = 0;)CPP";
> +c = R"Cpp(int * k = 0;)Cpp";
> +d = R"cpp(int * k = 0;)Cpp";)test",
> + MixedStyle));
> +}
> +
> +TEST_F(FormatTestRawStrings, ReformatsShortRawStringsOnSingleLine) {
> + expect_eq(
> + R"test(P p = TP(R"pb()pb");)test",
> + format(
> + R"test(P p = TP(R"pb( )pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> + expect_eq(
> + R"test(P p = TP(R"pb(item_1: 1)pb");)test",
> + format(
> + R"test(P p = TP(R"pb(item_1:1)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> + expect_eq(
> + R"test(P p = TP(R"pb(item_1: 1)pb");)test",
> + format(
> + R"test(P p = TP(R"pb( item_1 : 1 )pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> + expect_eq(
> + R"test(P p = TP(R"pb(item_1: 1 item_2: 2)pb");)test",
> + format(
> + R"test(P p = TP(R"pb(item_1:1 item_2:2)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> + expect_eq(
> + R"test(P p = TP(R"pb(item_1 <1> item_2: {2})pb");)test",
> + format(
> + R"test(P p = TP(R"pb(item_1<1> item_2:{2})pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Merge two short lines into one.
> + expect_eq(R"test(
> +std::string s = R"pb(
> + item_1: 1 item_2: 2
> +)pb";
> +)test",
> + format(R"test(
> +std::string s = R"pb(
> + item_1:1
> + item_2:2
> +)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +}
> +
> +TEST_F(FormatTestRawStrings, BreaksRawStringsExceedingColumnLimit) {
> + expect_eq(R"test(
> +P p = TPPPPPPPPPPPPPPP(
> + R"pb(item_1: 1, item_2: 2)pb");)test",
> + format(R"test(
> +P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +P p =
> + TPPPPPPPPPPPPPPP(
> + R"pb(item_1: 1,
> + item_2: 2,
> + item_3: 3)pb");)test",
> + format(R"test(
> +P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2, item_3: 3)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +P p = TP(R"pb(item_1 <1>
> + item_2: <2>
> + item_3 {})pb");)test",
> + format(R"test(
> +P p = TP(R"pb(item_1<1> item_2:<2> item_3{ })pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(
> + R"test(
> +P p = TP(R"pb(item_1: 1,
> + item_2: 2,
> + item_3: 3,
> + item_4: 4)pb");)test",
> + format(
> + R"test(
> +P p = TP(R"pb(item_1: 1, item_2: 2, item_3: 3, item_4: 4)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +P p = TPPPPPPPPPPPPPPP(
> + R"pb(item_1 <1>,
> + item_2: {2},
> + item_3: <3>,
> + item_4: {4})pb");)test",
> + format(R"test(
> +P p = TPPPPPPPPPPPPPPP(R"pb(item_1<1>, item_2: {2}, item_3: <3>,
> item_4:{4})pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Breaks before a short raw string exceeding the column limit.
> + expect_eq(R"test(
> +FFFFFFFFFFFFFFFFFFFFFFFFFFF(
> + R"pb(key: 1)pb");
> +P p = TPPPPPPPPPPPPPPPPPPPP(
> + R"pb(key: 2)pb");
> +auto TPPPPPPPPPPPPPPPPPPPP =
> + R"pb(key: 3)pb";
> +P p = TPPPPPPPPPPPPPPPPPPPP(
> + R"pb(i: 1, j: 2)pb");
> +
> +int f(string s) {
> + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(
> + R"pb(key: 1)pb");
> + P p = TPPPPPPPPPPPPPPPPPPPP(
> + R"pb(key: 2)pb");
> + auto TPPPPPPPPPPPPPPPPPPPP =
> + R"pb(key: 3)pb";
> + if (s.empty())
> + P p = TPPPPPPPPPPPPPPPPPPPP(
> + R"pb(i: 1, j: 2)pb");
> +}
> +)test",
> + format(R"test(
> +FFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb");
> +P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb");
> +auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb";
> +P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb");
> +
> +int f(string s) {
> + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb");
> + P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb");
> + auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb";
> + if (s.empty())
> + P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb");
> +}
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +}
> +
> +TEST_F(FormatTestRawStrings, FormatsRawStringArguments) {
> + expect_eq(R"test(
> +P p = TP(R"pb(key {1})pb", param_2);)test",
> + format(R"test(
> +P p = TP(R"pb(key{1})pb",param_2);)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +PPPPPPPPPPPPP(R"pb(keykeyk)pb",
> + param_2);)test",
> + format(R"test(
> +PPPPPPPPPPPPP(R"pb(keykeyk)pb", param_2);)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +P p =
> + TP(R"pb(item: {i: 1, s: 's'}
> + item: {i: 2, s: 't'})pb");)test",
> + format(R"test(
> +P p = TP(R"pb(item: {i: 1, s: 's'} item: {i: 2, s: 't'})pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> + expect_eq(R"test(
> +FFFFFFFFFFFFFFFFFFF(
> + R"pb(key: "value")pb",
> + R"pb(key2: "value")pb");)test",
> + format(R"test(
> +FFFFFFFFFFFFFFFFFFF(R"pb(key: "value")pb", R"pb(key2: "value")pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats the first out of two arguments.
> + expect_eq(R"test(
> +FFFFFFFF(R"pb(key: 1)pb", argument2);
> +struct S {
> + const s =
> + f(R"pb(key: 1)pb", argument2);
> + void f() {
> + if (gol)
> + return g(R"pb(key: 1)pb",
> + 132789237);
> + return g(R"pb(key: 1)pb", "172893");
> + }
> +};)test",
> + format(R"test(
> +FFFFFFFF(R"pb(key:1)pb", argument2);
> +struct S {
> +const s = f(R"pb(key:1)pb", argument2);
> +void f() {
> + if (gol)
> + return g(R"pb(key:1)pb", 132789237);
> + return g(R"pb(key:1)pb", "172893");
> +}
> +};)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats the second out of two arguments.
> + expect_eq(R"test(
> +FFFFFFFF(argument1, R"pb(key: 2)pb");
> +struct S {
> + const s =
> + f(argument1, R"pb(key: 2)pb");
> + void f() {
> + if (gol)
> + return g(12784137,
> + R"pb(key: 2)pb");
> + return g(17283122, R"pb(key: 2)pb");
> + }
> +};)test",
> + format(R"test(
> +FFFFFFFF(argument1, R"pb(key:2)pb");
> +struct S {
> +const s = f(argument1, R"pb(key:2)pb");
> +void f() {
> + if (gol)
> + return g(12784137, R"pb(key:2)pb");
> + return g(17283122, R"pb(key:2)pb");
> +}
> +};)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats two short raw string arguments.
> + expect_eq(R"test(
> +FFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test",
> + format(R"test(
> +FFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> + // TODO(krasimir): The original source code fits on one line, so the
> + // non-optimizing formatter is chosen. But after the formatting in
> protos is
> + // made, the code doesn't fit on one line anymore and further formatting
> + // splits it.
> + //
> + // Should we disable raw string formatting for the non-optimizing
> formatter?
> + expect_eq(R"test(
> +FFFFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test",
> + format(R"test(
> +FFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats two short raw string arguments, puts second on newline.
> + expect_eq(R"test(
> +FFFFFFFF(R"pb(key: 1)pb",
> + R"pb(key: 2)pb");)test",
> + format(R"test(
> +FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats both arguments.
> + expect_eq(R"test(
> +FFFFFFFF(R"pb(key: 1)pb",
> + R"pb(key: 2)pb");
> +struct S {
> + const s = f(R"pb(key: 1)pb",
> + R"pb(key: 2)pb");
> + void f() {
> + if (gol)
> + return g(R"pb(key: 1)pb",
> + R"pb(key: 2)pb");
> + return g(R"pb(k1)pb", R"pb(k2)pb");
> + }
> +};)test",
> + format(R"test(
> +FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");
> +struct S {
> +const s = f(R"pb(key:1)pb", R"pb(key:2)pb");
> +void f() {
> + if (gol)
> + return g(R"pb(key:1)pb", R"pb(key:2)pb");
> + return g(R"pb( k1 )pb", R"pb( k2 )pb");
> +}
> +};)test",
> + getRawStringPbStyleWithColumns(40)));
> +}
> +
> +TEST_F(FormatTestRawStrings, RawStringStartingWithNewlines) {
> + expect_eq(R"test(
> +std::string s = R"pb(
> + item_1: 1
> +)pb";
> +)test",
> + format(R"test(
> +std::string s = R"pb(
> + item_1:1
> +)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +std::string s = R"pb(
> +
> + item_1: 1
> +)pb";
> +)test",
> + format(R"test(
> +std::string s = R"pb(
> +
> + item_1:1
> +)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +std::string s = R"pb(
> + item_1: 1
> +)pb";
> +)test",
> + format(R"test(
> +std::string s = R"pb(
> + item_1:1
> +
> +)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +std::string s = R"pb(
> + item_1: 1,
> + item_2: 2
> +)pb";
> +)test",
> + format(R"test(
> +std::string s = R"pb(
> + item_1:1, item_2:2
> +)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +std::string s = R"pb(
> + book {
> + title: "Alice's Adventures"
> + author: "Lewis Caroll"
> + }
> + book {
> + title: "Peter Pan"
> + author: "J. M. Barrie"
> + }
> +)pb";
> +)test",
> + format(R"test(
> +std::string s = R"pb(
> + book { title: "Alice's Adventures" author: "Lewis Caroll" }
> + book { title: "Peter Pan" author: "J. M. Barrie" }
> +)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +}
> +
> +TEST_F(FormatTestRawStrings, BreaksBeforeRawStrings) {
> + expect_eq(R"test(
> +ASSERT_TRUE(
> + ParseFromString(R"pb(item_1: 1)pb"),
> + ptr);)test",
> + format(R"test(
> +ASSERT_TRUE(ParseFromString(R"pb(item_1: 1)pb"), ptr);)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +ASSERT_TRUE(toolong::ParseFromString(
> + R"pb(item_1: 1)pb"),
> + ptr);)test",
> + format(R"test(
> +ASSERT_TRUE(toolong::ParseFromString(R"pb(item_1: 1)pb"), ptr);)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +ASSERT_TRUE(ParseFromString(
> + R"pb(item_1: 1,
> + item_2: 2)pb"),
> + ptr);)test",
> + format(R"test(
> +ASSERT_TRUE(ParseFromString(R"pb(item_1: 1, item_2: 2)pb"), ptr);)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +ASSERT_TRUE(
> + ParseFromString(
> + R"pb(item_1: 1 item_2: 2)pb"),
> + ptr);)test",
> + format(R"test(
> +ASSERT_TRUE(ParseFromString(R"pb(item_1: 1 item_2: 2)pb"), ptr);)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> +}
> +
> +TEST_F(FormatTestRawStrings, RawStringsInOperands) {
> + // Formats the raw string first operand of a binary operator expression.
> + expect_eq(R"test(auto S = R"pb(item_1: 1)pb" + rest;)test",
> + format(R"test(auto S = R"pb(item_1:1)pb" + rest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1, item_2: 2)pb" +
> + rest;)test",
> + format(R"test(
> +auto S = R"pb(item_1:1,item_2:2)pb"+rest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S =
> + R"pb(item_1: 1 item_2: 2)pb" + rest;)test",
> + format(R"test(
> +auto S = R"pb(item_1:1 item_2:2)pb"+rest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1,
> + item_2: 2,
> + item_3: 3)pb" + rest;)test",
> + format(R"test(
> +auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1,
> + item_2: 2,
> + item_3: 3)pb" +
> + longlongrest;)test",
> + format(R"test(
> +auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats the raw string second operand of a binary operator
> expression.
> + expect_eq(R"test(auto S = first + R"pb(item_1: 1)pb";)test",
> + format(R"test(auto S = first + R"pb(item_1:1)pb";)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = first + R"pb(item_1: 1,
> + item_2: 2)pb";)test",
> + format(R"test(
> +auto S = first+R"pb(item_1:1,item_2:2)pb";)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = first + R"pb(item_1: 1
> + item_2: 2)pb";)test",
> + format(R"test(
> +auto S = first+R"pb(item_1:1 item_2:2)pb";)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1,
> + item_2: 2,
> + item_3: 3)pb" + rest;)test",
> + format(R"test(
> +auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1,
> + item_2: 2,
> + item_3: 3)pb" +
> + longlongrest;)test",
> + format(R"test(
> +auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + // Formats the raw string operands in expressions.
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1)pb" +
> + R"pb(item_2: 2)pb";
> +)test",
> + format(R"test(
> +auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = R"pb(item_1: 1)pb" +
> + R"pb(item_2: 2)pb" +
> + R"pb(item_3: 3)pb";
> +)test",
> + format(R"test(
> +auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb"+R"pb(item_3:3)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S = (count < 3)
> + ? R"pb(item_1: 1)pb"
> + : R"pb(item_2: 2)pb";
> +)test",
> + format(R"test(
> +auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S =
> + (count < 3)
> + ? R"pb(item_1: 1, item_2: 2)pb"
> + : R"pb(item_3: 3)pb";
> +)test",
> + format(R"test(
> +auto S=(count<3)?R"pb(item_1:1,item_2:2)pb":R"pb(item_3:3)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> + expect_eq(R"test(
> +auto S =
> + (count < 3)
> + ? R"pb(item_1: 1)pb"
> + : R"pb(item_2: 2, item_3: 3)pb";
> +)test",
> + format(R"test(
> +auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2,item_3:3)pb";
> +)test",
> + getRawStringPbStyleWithColumns(40)));
> +
> +}
> +
> +TEST_F(FormatTestRawStrings, PrefixAndSuffixAlignment) {
> + // Keep the suffix at the end of line if not on newline.
> + expect_eq(R"test(
> +int s() {
> + auto S = PTP(
> + R"pb(
> + item_1: 1,
> + item_2: 2)pb");
> +})test",
> + format(R"test(
> +int s() {
> + auto S = PTP(
> + R"pb(
> + item_1: 1,
> + item_2: 2)pb");
> +})test",
> + getRawStringPbStyleWithColumns(20)));
> +
> + // Align the suffix with the surrounding FirstIndent if the prefix is
> not on
> + // a line of its own.
> + expect_eq(R"test(
> +int s() {
> + auto S = PTP(
> + R"pb(
> + item_1: 1,
> + item_2: 2
> + )pb");
> +})test",
> + format(R"test(
> +int s() {
> + auto S = PTP(R"pb(
> + item_1: 1,
> + item_2: 2
> + )pb");
> +})test",
> + getRawStringPbStyleWithColumns(20)));
> +
> + // Align the prefix with the suffix if both the prefix and suffix are
> on a
> + // line of their own.
> + expect_eq(R"test(
> +int s() {
> + auto S = PTP(
> + R"pb(
> + item_1: 1,
> + item_2: 2,
> + )pb");
> +})test",
> + format(R"test(
> +int s() {
> + auto S = PTP(
> + R"pb(
> + item_1: 1,
> + item_2: 2,
> + )pb");
> +})test",
> + getRawStringPbStyleWithColumns(20)));
> +}
> +
> +TEST_F(FormatTestRawStrings, EstimatesPenalty) {
> + // The penalty for characters exceeding the column limit in the raw
> string
> + // forces 'hh' to be put on a newline.
> + expect_eq(R"test(
> +ff(gggggg,
> + hh(R"pb(key {
> + i1: k1
> + i2: k2
> + })pb"));
> +)test",
> + format(R"test(
> +ff(gggggg, hh(R"pb(key {
> + i1: k1
> + i2: k2
> + })pb"));
> +)test",
> + getRawStringPbStyleWithColumns(20)));
> +}
> +
> +TEST_F(FormatTestRawStrings, DontFormatNonRawStrings) {
> + expect_eq(R"test(a = R"pb(key:value)";)test",
> + format(R"test(a = R"pb(key:value)";)test",
> + getRawStringPbStyleWithColumns(20)));
> +}
> +
> +} // end namespace
> +} // end namespace format
> +} // end namespace clang
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20171030/7376d2e2/attachment-0001.html>
More information about the cfe-commits
mailing list