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