diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Format/Format.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Format/Format.cpp | 1192 | 
1 files changed, 917 insertions, 275 deletions
| diff --git a/contrib/llvm/tools/clang/lib/Format/Format.cpp b/contrib/llvm/tools/clang/lib/Format/Format.cpp index 01c122ecc7bf..58dd5604e427 100644 --- a/contrib/llvm/tools/clang/lib/Format/Format.cpp +++ b/contrib/llvm/tools/clang/lib/Format/Format.cpp @@ -13,84 +13,131 @@  ///  //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "format-formatter" -  #include "ContinuationIndenter.h"  #include "TokenAnnotator.h"  #include "UnwrappedLineParser.h"  #include "WhitespaceManager.h"  #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h"  #include "clang/Basic/SourceManager.h"  #include "clang/Format/Format.h"  #include "clang/Lex/Lexer.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/Support/Allocator.h"  #include "llvm/Support/Debug.h" -#include "llvm/Support/YAMLTraits.h"  #include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h"  #include <queue>  #include <string> +#define DEBUG_TYPE "format-formatter" + +using clang::format::FormatStyle; + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) +  namespace llvm {  namespace yaml { -template <> -struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> { -  static void enumeration(IO &IO, -                          clang::format::FormatStyle::LanguageStandard &Value) { -    IO.enumCase(Value, "Cpp03", clang::format::FormatStyle::LS_Cpp03); -    IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03); -    IO.enumCase(Value, "Cpp11", clang::format::FormatStyle::LS_Cpp11); -    IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11); -    IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto); +template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { +  static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) { +    IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp); +    IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript); +    IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); +  } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> { +  static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) { +    IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03); +    IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); +    IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11); +    IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); +    IO.enumCase(Value, "Auto", FormatStyle::LS_Auto); +  } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> { +  static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) { +    IO.enumCase(Value, "Never", FormatStyle::UT_Never); +    IO.enumCase(Value, "false", FormatStyle::UT_Never); +    IO.enumCase(Value, "Always", FormatStyle::UT_Always); +    IO.enumCase(Value, "true", FormatStyle::UT_Always); +    IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation); +  } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> { +  static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { +    IO.enumCase(Value, "None", FormatStyle::SFS_None); +    IO.enumCase(Value, "false", FormatStyle::SFS_None); +    IO.enumCase(Value, "All", FormatStyle::SFS_All); +    IO.enumCase(Value, "true", FormatStyle::SFS_All); +    IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline); +  } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { +  static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) { +    IO.enumCase(Value, "Attach", FormatStyle::BS_Attach); +    IO.enumCase(Value, "Linux", FormatStyle::BS_Linux); +    IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup); +    IO.enumCase(Value, "Allman", FormatStyle::BS_Allman); +    IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);    }  };  template <> -struct ScalarEnumerationTraits<clang::format::FormatStyle::UseTabStyle> { +struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {    static void enumeration(IO &IO, -                          clang::format::FormatStyle::UseTabStyle &Value) { -    IO.enumCase(Value, "Never", clang::format::FormatStyle::UT_Never); -    IO.enumCase(Value, "false", clang::format::FormatStyle::UT_Never); -    IO.enumCase(Value, "Always", clang::format::FormatStyle::UT_Always); -    IO.enumCase(Value, "true", clang::format::FormatStyle::UT_Always); -    IO.enumCase(Value, "ForIndentation", -                clang::format::FormatStyle::UT_ForIndentation); +                          FormatStyle::NamespaceIndentationKind &Value) { +    IO.enumCase(Value, "None", FormatStyle::NI_None); +    IO.enumCase(Value, "Inner", FormatStyle::NI_Inner); +    IO.enumCase(Value, "All", FormatStyle::NI_All);    }  };  template <> -struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> { -  static void -  enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) { -    IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach); -    IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux); -    IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup); -    IO.enumCase(Value, "Allman", clang::format::FormatStyle::BS_Allman); +struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { +  static void enumeration(IO &IO, +                          FormatStyle::PointerAlignmentStyle &Value) { +    IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle); +    IO.enumCase(Value, "Left", FormatStyle::PAS_Left); +    IO.enumCase(Value, "Right", FormatStyle::PAS_Right); + +    // For backward compatibility. +    IO.enumCase(Value, "true", FormatStyle::PAS_Left); +    IO.enumCase(Value, "false", FormatStyle::PAS_Right);    }  };  template <> -struct ScalarEnumerationTraits< -    clang::format::FormatStyle::NamespaceIndentationKind> { -  static void -  enumeration(IO &IO, -              clang::format::FormatStyle::NamespaceIndentationKind &Value) { -    IO.enumCase(Value, "None", clang::format::FormatStyle::NI_None); -    IO.enumCase(Value, "Inner", clang::format::FormatStyle::NI_Inner); -    IO.enumCase(Value, "All", clang::format::FormatStyle::NI_All); +struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> { +  static void enumeration(IO &IO, +                          FormatStyle::SpaceBeforeParensOptions &Value) { +    IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); +    IO.enumCase(Value, "ControlStatements", +                FormatStyle::SBPO_ControlStatements); +    IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); + +    // For backward compatibility. +    IO.enumCase(Value, "false", FormatStyle::SBPO_Never); +    IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);    }  }; -template <> struct MappingTraits<clang::format::FormatStyle> { -  static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) { +template <> struct MappingTraits<FormatStyle> { +  static void mapping(IO &IO, FormatStyle &Style) { +    // When reading, read the language first, we need it for getPredefinedStyle. +    IO.mapOptional("Language", Style.Language); +      if (IO.outputting()) {        StringRef StylesArray[] = { "LLVM",    "Google", "Chromium", -                                  "Mozilla", "WebKit" }; +                                  "Mozilla", "WebKit", "GNU" };        ArrayRef<StringRef> Styles(StylesArray);        for (size_t i = 0, e = Styles.size(); i < e; ++i) {          StringRef StyleName(Styles[i]); -        clang::format::FormatStyle PredefinedStyle; -        if (clang::format::getPredefinedStyle(StyleName, &PredefinedStyle) && +        FormatStyle PredefinedStyle; +        if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&              Style == PredefinedStyle) {            IO.mapOptional("# BasedOnStyle", StyleName);            break; @@ -99,11 +146,16 @@ template <> struct MappingTraits<clang::format::FormatStyle> {      } else {        StringRef BasedOnStyle;        IO.mapOptional("BasedOnStyle", BasedOnStyle); -      if (!BasedOnStyle.empty()) -        if (!clang::format::getPredefinedStyle(BasedOnStyle, &Style)) { +      if (!BasedOnStyle.empty()) { +        FormatStyle::LanguageKind OldLanguage = Style.Language; +        FormatStyle::LanguageKind Language = +            ((FormatStyle *)IO.getContext())->Language; +        if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {            IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));            return;          } +        Style.Language = OldLanguage; +      }      }      IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset); @@ -113,10 +165,14 @@ template <> struct MappingTraits<clang::format::FormatStyle> {      IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);      IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",                     Style.AllowAllParametersOfDeclarationOnNextLine); +    IO.mapOptional("AllowShortBlocksOnASingleLine", +                   Style.AllowShortBlocksOnASingleLine);      IO.mapOptional("AllowShortIfStatementsOnASingleLine",                     Style.AllowShortIfStatementsOnASingleLine);      IO.mapOptional("AllowShortLoopsOnASingleLine",                     Style.AllowShortLoopsOnASingleLine); +    IO.mapOptional("AllowShortFunctionsOnASingleLine", +                   Style.AllowShortFunctionsOnASingleLine);      IO.mapOptional("AlwaysBreakTemplateDeclarations",                     Style.AlwaysBreakTemplateDeclarations);      IO.mapOptional("AlwaysBreakBeforeMultilineStrings", @@ -131,12 +187,19 @@ template <> struct MappingTraits<clang::format::FormatStyle> {      IO.mapOptional("ColumnLimit", Style.ColumnLimit);      IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",                     Style.ConstructorInitializerAllOnOneLineOrOnePerLine); -    IO.mapOptional("DerivePointerBinding", Style.DerivePointerBinding); +    IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);      IO.mapOptional("ExperimentalAutoDetectBinPacking",                     Style.ExperimentalAutoDetectBinPacking);      IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); +    IO.mapOptional("IndentWrappedFunctionNames", +                   Style.IndentWrappedFunctionNames); +    IO.mapOptional("IndentFunctionDeclarationAfterType", +                   Style.IndentWrappedFunctionNames);      IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); +    IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", +                   Style.KeepEmptyLinesAtTheStartOfBlocks);      IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); +    IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);      IO.mapOptional("ObjCSpaceBeforeProtocolList",                     Style.ObjCSpaceBeforeProtocolList);      IO.mapOptional("PenaltyBreakBeforeFirstCallParameter", @@ -148,7 +211,7 @@ template <> struct MappingTraits<clang::format::FormatStyle> {      IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);      IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",                     Style.PenaltyReturnTypeOnItsOwnLine); -    IO.mapOptional("PointerBindsToType", Style.PointerBindsToType); +    IO.mapOptional("PointerAlignment", Style.PointerAlignment);      IO.mapOptional("SpacesBeforeTrailingComments",                     Style.SpacesBeforeTrailingComments);      IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle); @@ -157,18 +220,54 @@ template <> struct MappingTraits<clang::format::FormatStyle> {      IO.mapOptional("TabWidth", Style.TabWidth);      IO.mapOptional("UseTab", Style.UseTab);      IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); -    IO.mapOptional("IndentFunctionDeclarationAfterType", -                   Style.IndentFunctionDeclarationAfterType);      IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);      IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);      IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);      IO.mapOptional("SpacesInCStyleCastParentheses",                     Style.SpacesInCStyleCastParentheses); -    IO.mapOptional("SpaceAfterControlStatementKeyword", -                   Style.SpaceAfterControlStatementKeyword); +    IO.mapOptional("SpacesInContainerLiterals", +                   Style.SpacesInContainerLiterals);      IO.mapOptional("SpaceBeforeAssignmentOperators",                     Style.SpaceBeforeAssignmentOperators);      IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); +    IO.mapOptional("CommentPragmas", Style.CommentPragmas); +    IO.mapOptional("ForEachMacros", Style.ForEachMacros); + +    // For backward compatibility. +    if (!IO.outputting()) { +      IO.mapOptional("SpaceAfterControlStatementKeyword", +                     Style.SpaceBeforeParens); +      IO.mapOptional("PointerBindsToType", Style.PointerAlignment); +      IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment); +    } +    IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); +    IO.mapOptional("DisableFormat", Style.DisableFormat); +  } +}; + +// 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. +// If the first element has no Language specified, it will be treated as the +// default one for the following elements. +template <> struct DocumentListTraits<std::vector<FormatStyle> > { +  static size_t size(IO &IO, std::vector<FormatStyle> &Seq) { +    return Seq.size(); +  } +  static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq, +                              size_t Index) { +    if (Index >= Seq.size()) { +      assert(Index == Seq.size()); +      FormatStyle Template; +      if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) { +        Template = Seq[0]; +      } else { +        Template = *((const FormatStyle *)IO.getContext()); +        Template.Language = FormatStyle::LK_None; +      } +      Seq.resize(Index + 1, Template); +    } +    return Seq[Index];    }  };  } @@ -177,19 +276,39 @@ template <> struct MappingTraits<clang::format::FormatStyle> {  namespace clang {  namespace format { -void setDefaultPenalties(FormatStyle &Style) { -  Style.PenaltyBreakComment = 60; -  Style.PenaltyBreakFirstLessLess = 120; -  Style.PenaltyBreakString = 1000; -  Style.PenaltyExcessCharacter = 1000000; +const std::error_category &getParseCategory() { +  static ParseErrorCategory C; +  return C; +} +std::error_code make_error_code(ParseError e) { +  return std::error_code(static_cast<int>(e), getParseCategory()); +} + +const char *ParseErrorCategory::name() const LLVM_NOEXCEPT { +  return "clang-format.parse_error"; +} + +std::string ParseErrorCategory::message(int EV) const { +  switch (static_cast<ParseError>(EV)) { +  case ParseError::Success: +    return "Success"; +  case ParseError::Error: +    return "Invalid argument"; +  case ParseError::Unsuitable: +    return "Unsuitable"; +  } +  llvm_unreachable("unexpected parse error");  }  FormatStyle getLLVMStyle() {    FormatStyle LLVMStyle; +  LLVMStyle.Language = FormatStyle::LK_Cpp;    LLVMStyle.AccessModifierOffset = -2;    LLVMStyle.AlignEscapedNewlinesLeft = false;    LLVMStyle.AlignTrailingComments = true;    LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; +  LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; +  LLVMStyle.AllowShortBlocksOnASingleLine = false;    LLVMStyle.AllowShortIfStatementsOnASingleLine = false;    LLVMStyle.AllowShortLoopsOnASingleLine = false;    LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; @@ -200,91 +319,92 @@ FormatStyle getLLVMStyle() {    LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;    LLVMStyle.BreakConstructorInitializersBeforeComma = false;    LLVMStyle.ColumnLimit = 80; +  LLVMStyle.CommentPragmas = "^ IWYU pragma:";    LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;    LLVMStyle.ConstructorInitializerIndentWidth = 4; -  LLVMStyle.Cpp11BracedListStyle = false; -  LLVMStyle.DerivePointerBinding = false; +  LLVMStyle.ContinuationIndentWidth = 4; +  LLVMStyle.Cpp11BracedListStyle = true; +  LLVMStyle.DerivePointerAlignment = false;    LLVMStyle.ExperimentalAutoDetectBinPacking = false; +  LLVMStyle.ForEachMacros.push_back("foreach"); +  LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); +  LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");    LLVMStyle.IndentCaseLabels = false; -  LLVMStyle.IndentFunctionDeclarationAfterType = false; +  LLVMStyle.IndentWrappedFunctionNames = false;    LLVMStyle.IndentWidth = 2;    LLVMStyle.TabWidth = 8;    LLVMStyle.MaxEmptyLinesToKeep = 1; +  LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;    LLVMStyle.NamespaceIndentation = FormatStyle::NI_None; +  LLVMStyle.ObjCSpaceAfterProperty = false;    LLVMStyle.ObjCSpaceBeforeProtocolList = true; -  LLVMStyle.PointerBindsToType = false; +  LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;    LLVMStyle.SpacesBeforeTrailingComments = 1; -  LLVMStyle.Standard = FormatStyle::LS_Cpp03; +  LLVMStyle.Standard = FormatStyle::LS_Cpp11;    LLVMStyle.UseTab = FormatStyle::UT_Never;    LLVMStyle.SpacesInParentheses = false;    LLVMStyle.SpaceInEmptyParentheses = false; +  LLVMStyle.SpacesInContainerLiterals = true;    LLVMStyle.SpacesInCStyleCastParentheses = false; -  LLVMStyle.SpaceAfterControlStatementKeyword = true; +  LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;    LLVMStyle.SpaceBeforeAssignmentOperators = true; -  LLVMStyle.ContinuationIndentWidth = 4;    LLVMStyle.SpacesInAngles = false; -  setDefaultPenalties(LLVMStyle); +  LLVMStyle.PenaltyBreakComment = 300; +  LLVMStyle.PenaltyBreakFirstLessLess = 120; +  LLVMStyle.PenaltyBreakString = 1000; +  LLVMStyle.PenaltyExcessCharacter = 1000000;    LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;    LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; +  LLVMStyle.DisableFormat = false; +    return LLVMStyle;  } -FormatStyle getGoogleStyle() { -  FormatStyle GoogleStyle; +FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { +  FormatStyle GoogleStyle = getLLVMStyle(); +  GoogleStyle.Language = Language; +    GoogleStyle.AccessModifierOffset = -1;    GoogleStyle.AlignEscapedNewlinesLeft = true; -  GoogleStyle.AlignTrailingComments = true; -  GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;    GoogleStyle.AllowShortIfStatementsOnASingleLine = true;    GoogleStyle.AllowShortLoopsOnASingleLine = true;    GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;    GoogleStyle.AlwaysBreakTemplateDeclarations = true; -  GoogleStyle.BinPackParameters = true; -  GoogleStyle.BreakBeforeBinaryOperators = false; -  GoogleStyle.BreakBeforeTernaryOperators = true; -  GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach; -  GoogleStyle.BreakConstructorInitializersBeforeComma = false; -  GoogleStyle.ColumnLimit = 80;    GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; -  GoogleStyle.ConstructorInitializerIndentWidth = 4; -  GoogleStyle.Cpp11BracedListStyle = true; -  GoogleStyle.DerivePointerBinding = true; -  GoogleStyle.ExperimentalAutoDetectBinPacking = false; +  GoogleStyle.DerivePointerAlignment = true;    GoogleStyle.IndentCaseLabels = true; -  GoogleStyle.IndentFunctionDeclarationAfterType = true; -  GoogleStyle.IndentWidth = 2; -  GoogleStyle.TabWidth = 8; -  GoogleStyle.MaxEmptyLinesToKeep = 1; -  GoogleStyle.NamespaceIndentation = FormatStyle::NI_None; +  GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false; +  GoogleStyle.ObjCSpaceAfterProperty = false;    GoogleStyle.ObjCSpaceBeforeProtocolList = false; -  GoogleStyle.PointerBindsToType = true; +  GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;    GoogleStyle.SpacesBeforeTrailingComments = 2;    GoogleStyle.Standard = FormatStyle::LS_Auto; -  GoogleStyle.UseTab = FormatStyle::UT_Never; -  GoogleStyle.SpacesInParentheses = false; -  GoogleStyle.SpaceInEmptyParentheses = false; -  GoogleStyle.SpacesInCStyleCastParentheses = false; -  GoogleStyle.SpaceAfterControlStatementKeyword = true; -  GoogleStyle.SpaceBeforeAssignmentOperators = true; -  GoogleStyle.ContinuationIndentWidth = 4; -  GoogleStyle.SpacesInAngles = false; - -  setDefaultPenalties(GoogleStyle); +    GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;    GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1; +  if (Language == FormatStyle::LK_JavaScript) { +    GoogleStyle.BreakBeforeTernaryOperators = false; +    GoogleStyle.MaxEmptyLinesToKeep = 3; +    GoogleStyle.SpacesInContainerLiterals = false; +  } else if (Language == FormatStyle::LK_Proto) { +    GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; +    GoogleStyle.SpacesInContainerLiterals = false; +  } +    return GoogleStyle;  } -FormatStyle getChromiumStyle() { -  FormatStyle ChromiumStyle = getGoogleStyle(); +FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) { +  FormatStyle ChromiumStyle = getGoogleStyle(Language);    ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false; +  ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;    ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;    ChromiumStyle.AllowShortLoopsOnASingleLine = false;    ChromiumStyle.BinPackParameters = false; -  ChromiumStyle.DerivePointerBinding = false; +  ChromiumStyle.DerivePointerAlignment = false;    ChromiumStyle.Standard = FormatStyle::LS_Cpp03;    return ChromiumStyle;  } @@ -292,12 +412,15 @@ FormatStyle getChromiumStyle() {  FormatStyle getMozillaStyle() {    FormatStyle MozillaStyle = getLLVMStyle();    MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false; +  MozillaStyle.Cpp11BracedListStyle = false;    MozillaStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; -  MozillaStyle.DerivePointerBinding = true; +  MozillaStyle.DerivePointerAlignment = true;    MozillaStyle.IndentCaseLabels = true; +  MozillaStyle.ObjCSpaceAfterProperty = true;    MozillaStyle.ObjCSpaceBeforeProtocolList = false;    MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; -  MozillaStyle.PointerBindsToType = true; +  MozillaStyle.PointerAlignment = FormatStyle::PAS_Left; +  MozillaStyle.Standard = FormatStyle::LS_Cpp03;    return MozillaStyle;  } @@ -308,36 +431,102 @@ FormatStyle getWebKitStyle() {    Style.BreakBeforeBinaryOperators = true;    Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;    Style.BreakConstructorInitializersBeforeComma = true; +  Style.Cpp11BracedListStyle = false;    Style.ColumnLimit = 0;    Style.IndentWidth = 4;    Style.NamespaceIndentation = FormatStyle::NI_Inner; -  Style.PointerBindsToType = true; +  Style.ObjCSpaceAfterProperty = true; +  Style.PointerAlignment = FormatStyle::PAS_Left; +  Style.Standard = FormatStyle::LS_Cpp03; +  return Style; +} + +FormatStyle getGNUStyle() { +  FormatStyle Style = getLLVMStyle(); +  Style.BreakBeforeBinaryOperators = true; +  Style.BreakBeforeBraces = FormatStyle::BS_GNU; +  Style.BreakBeforeTernaryOperators = true; +  Style.Cpp11BracedListStyle = false; +  Style.ColumnLimit = 79; +  Style.SpaceBeforeParens = FormatStyle::SBPO_Always; +  Style.Standard = FormatStyle::LS_Cpp03;    return Style;  } -bool getPredefinedStyle(StringRef Name, FormatStyle *Style) { -  if (Name.equals_lower("llvm")) +FormatStyle getNoStyle() { +  FormatStyle NoStyle = getLLVMStyle(); +  NoStyle.DisableFormat = true; +  return NoStyle; +} + +bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language, +                        FormatStyle *Style) { +  if (Name.equals_lower("llvm")) {      *Style = getLLVMStyle(); -  else if (Name.equals_lower("chromium")) -    *Style = getChromiumStyle(); -  else if (Name.equals_lower("mozilla")) +  } else if (Name.equals_lower("chromium")) { +    *Style = getChromiumStyle(Language); +  } else if (Name.equals_lower("mozilla")) {      *Style = getMozillaStyle(); -  else if (Name.equals_lower("google")) -    *Style = getGoogleStyle(); -  else if (Name.equals_lower("webkit")) +  } else if (Name.equals_lower("google")) { +    *Style = getGoogleStyle(Language); +  } else if (Name.equals_lower("webkit")) {      *Style = getWebKitStyle(); -  else +  } else if (Name.equals_lower("gnu")) { +    *Style = getGNUStyle(); +  } else if (Name.equals_lower("none")) { +    *Style = getNoStyle(); +  } else {      return false; +  } +  Style->Language = Language;    return true;  } -llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) { +std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) { +  assert(Style); +  FormatStyle::LanguageKind Language = Style->Language; +  assert(Language != FormatStyle::LK_None);    if (Text.trim().empty()) -    return llvm::make_error_code(llvm::errc::invalid_argument); +    return make_error_code(ParseError::Error); + +  std::vector<FormatStyle> Styles;    llvm::yaml::Input Input(Text); -  Input >> *Style; -  return Input.error(); +  // DocumentListTraits<vector<FormatStyle>> uses the context to get default +  // values for the fields, keys for which are missing from the configuration. +  // Mapping also uses the context to get the language to find the correct +  // base style. +  Input.setContext(Style); +  Input >> Styles; +  if (Input.error()) +    return Input.error(); + +  for (unsigned i = 0; i < Styles.size(); ++i) { +    // Ensures that only the first configuration can skip the Language option. +    if (Styles[i].Language == FormatStyle::LK_None && i != 0) +      return make_error_code(ParseError::Error); +    // Ensure that each language is configured at most once. +    for (unsigned j = 0; j < i; ++j) { +      if (Styles[i].Language == Styles[j].Language) { +        DEBUG(llvm::dbgs() +              << "Duplicate languages in the config file on positions " << j +              << " and " << i << "\n"); +        return make_error_code(ParseError::Error); +      } +    } +  } +  // Look for a suitable configuration starting from the end, so we can +  // find the configuration for the specific language first, and the default +  // configuration (which can only be at slot 0) after it. +  for (int i = Styles.size() - 1; i >= 0; --i) { +    if (Styles[i].Language == Language || +        Styles[i].Language == FormatStyle::LK_None) { +      *Style = Styles[i]; +      Style->Language = Language; +      return make_error_code(ParseError::Success); +    } +  } +  return make_error_code(ParseError::Unsuitable);  }  std::string configurationAsText(const FormatStyle &Style) { @@ -362,7 +551,7 @@ public:    void format(unsigned FirstIndent, const AnnotatedLine *Line) {      LineState State =          Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false); -    while (State.NextToken != NULL) { +    while (State.NextToken) {        bool Newline =            Indenter->mustBreak(State) ||            (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0); @@ -381,14 +570,14 @@ public:    /// \brief Calculates how many lines can be merged into 1 starting at \p I.    unsigned    tryFitMultipleLinesInOne(unsigned Indent, -                           SmallVectorImpl<AnnotatedLine *>::const_iterator &I, +                           SmallVectorImpl<AnnotatedLine *>::const_iterator I,                             SmallVectorImpl<AnnotatedLine *>::const_iterator E) {      // We can never merge stuff if there are trailing line comments. -    AnnotatedLine *TheLine = *I; +    const AnnotatedLine *TheLine = *I;      if (TheLine->Last->Type == TT_LineComment)        return 0; -    if (Indent > Style.ColumnLimit) +    if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)        return 0;      unsigned Limit = @@ -399,19 +588,54 @@ public:                  ? 0                  : Limit - TheLine->Last->TotalLength; -    if (I + 1 == E || I[1]->Type == LT_Invalid) +    if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)        return 0; +    // FIXME: TheLine->Level != 0 might or might not be the right check to do. +    // If necessary, change to something smarter. +    bool MergeShortFunctions = +        Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All || +        (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline && +         TheLine->Level != 0); + +    if (TheLine->Last->Type == TT_FunctionLBrace && +        TheLine->First != TheLine->Last) { +      return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0; +    }      if (TheLine->Last->is(tok::l_brace)) { -      return tryMergeSimpleBlock(I, E, Limit); -    } else if (Style.AllowShortIfStatementsOnASingleLine && -               TheLine->First->is(tok::kw_if)) { -      return tryMergeSimpleControlStatement(I, E, Limit); -    } else if (Style.AllowShortLoopsOnASingleLine && -               TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) { -      return tryMergeSimpleControlStatement(I, E, Limit); -    } else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline || -                                          TheLine->First->IsFirst)) { +      return Style.BreakBeforeBraces == FormatStyle::BS_Attach +                 ? tryMergeSimpleBlock(I, E, Limit) +                 : 0; +    } +    if (I[1]->First->Type == TT_FunctionLBrace && +        Style.BreakBeforeBraces != FormatStyle::BS_Attach) { +      // Check for Limit <= 2 to account for the " {". +      if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine))) +        return 0; +      Limit -= 2; + +      unsigned MergedLines = 0; +      if (MergeShortFunctions) { +        MergedLines = tryMergeSimpleBlock(I + 1, E, Limit); +        // If we managed to merge the block, count the function header, which is +        // on a separate line. +        if (MergedLines > 0) +          ++MergedLines; +      } +      return MergedLines; +    } +    if (TheLine->First->is(tok::kw_if)) { +      return Style.AllowShortIfStatementsOnASingleLine +                 ? tryMergeSimpleControlStatement(I, E, Limit) +                 : 0; +    } +    if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) { +      return Style.AllowShortLoopsOnASingleLine +                 ? tryMergeSimpleControlStatement(I, E, Limit) +                 : 0; +    } +    if (TheLine->InPPDirective && +        (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {        return tryMergeSimplePPDirective(I, E, Limit);      }      return 0; @@ -419,7 +643,7 @@ public:  private:    unsigned -  tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator &I, +  tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,                              SmallVectorImpl<AnnotatedLine *>::const_iterator E,                              unsigned Limit) {      if (Limit == 0) @@ -434,23 +658,25 @@ private:    }    unsigned tryMergeSimpleControlStatement( -      SmallVectorImpl<AnnotatedLine *>::const_iterator &I, +      SmallVectorImpl<AnnotatedLine *>::const_iterator I,        SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {      if (Limit == 0)        return 0; -    if (Style.BreakBeforeBraces == FormatStyle::BS_Allman && -        I[1]->First->is(tok::l_brace)) +    if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman || +         Style.BreakBeforeBraces == FormatStyle::BS_GNU) && +        (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))        return 0;      if (I[1]->InPPDirective != (*I)->InPPDirective ||          (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))        return 0; +    Limit = limitConsideringMacros(I + 1, E, Limit);      AnnotatedLine &Line = **I;      if (Line.Last->isNot(tok::r_paren))        return 0;      if (1 + I[1]->Last->TotalLength > Limit)        return 0;      if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, -                                   tok::kw_while) || +                             tok::kw_while) ||          I[1]->First->Type == TT_LineComment)        return 0;      // Only inline simple if's (no nested if or else). @@ -461,54 +687,69 @@ private:    }    unsigned -  tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator &I, +  tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,                        SmallVectorImpl<AnnotatedLine *>::const_iterator E,                        unsigned Limit) { -    // No merging if the brace already is on the next line. -    if (Style.BreakBeforeBraces != FormatStyle::BS_Attach) +    AnnotatedLine &Line = **I; + +    // Don't merge ObjC @ keywords and methods. +    if (Line.First->isOneOf(tok::at, tok::minus, tok::plus))        return 0; -    // First, check that the current line allows merging. This is the case if -    // we're not in a control flow statement and the last token is an opening -    // brace. -    AnnotatedLine &Line = **I; -    if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace, -                            tok::kw_else, tok::kw_try, tok::kw_catch, -                            tok::kw_for, -                            // This gets rid of all ObjC @ keywords and methods. -                            tok::at, tok::minus, tok::plus)) +    // Check that the current line allows merging. This depends on whether we +    // are in a control flow statements as well as several style flags. +    if (Line.First->isOneOf(tok::kw_else, tok::kw_case))        return 0; +    if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try, +                            tok::kw_catch, tok::kw_for, tok::r_brace)) { +      if (!Style.AllowShortBlocksOnASingleLine) +        return 0; +      if (!Style.AllowShortIfStatementsOnASingleLine && +          Line.First->is(tok::kw_if)) +        return 0; +      if (!Style.AllowShortLoopsOnASingleLine && +          Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for)) +        return 0; +      // FIXME: Consider an option to allow short exception handling clauses on +      // a single line. +      if (Line.First->isOneOf(tok::kw_try, tok::kw_catch)) +        return 0; +    }      FormatToken *Tok = I[1]->First;      if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore && -        (Tok->getNextNonComment() == NULL || +        (Tok->getNextNonComment() == nullptr ||           Tok->getNextNonComment()->is(tok::semi))) {        // We merge empty blocks even if the line exceeds the column limit.        Tok->SpacesRequiredBefore = 0;        Tok->CanBreakBefore = true;        return 1;      } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace)) { +      // We don't merge short records. +      if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct)) +        return 0; +        // Check that we still have three lines and they fit into the limit.        if (I + 2 == E || I[2]->Type == LT_Invalid)          return 0; +      Limit = limitConsideringMacros(I + 2, E, Limit);        if (!nextTwoLinesFitInto(I, Limit))          return 0;        // Second, check that the next line does not contain any braces - if it        // does, readability declines when putting it into a single line. -      if (I[1]->Last->Type == TT_LineComment || Tok->MustBreakBefore) +      if (I[1]->Last->Type == TT_LineComment)          return 0;        do { -        if (Tok->isOneOf(tok::l_brace, tok::r_brace)) +        if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)            return 0;          Tok = Tok->Next; -      } while (Tok != NULL); +      } while (Tok); -      // Last, check that the third line contains a single closing brace. +      // Last, check that the third line starts with a closing brace.        Tok = I[2]->First; -      if (Tok->getNextNonComment() != NULL || Tok->isNot(tok::r_brace) || -          Tok->MustBreakBefore) +      if (Tok->isNot(tok::r_brace))          return 0;        return 2; @@ -516,34 +757,60 @@ private:      return 0;    } +  /// Returns the modified column limit for \p I if it is inside a macro and +  /// needs a trailing '\'. +  unsigned +  limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I, +                         SmallVectorImpl<AnnotatedLine *>::const_iterator E, +                         unsigned Limit) { +    if (I[0]->InPPDirective && I + 1 != E && +        !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) { +      return Limit < 2 ? 0 : Limit - 2; +    } +    return Limit; +  } +    bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,                             unsigned Limit) { +    if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore) +      return false;      return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;    } +  bool containsMustBreak(const AnnotatedLine *Line) { +    for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) { +      if (Tok->MustBreakBefore) +        return true; +    } +    return false; +  } +    const FormatStyle &Style;  };  class UnwrappedLineFormatter {  public: -  UnwrappedLineFormatter(SourceManager &SourceMgr, -                         SmallVectorImpl<CharSourceRange> &Ranges, -                         ContinuationIndenter *Indenter, +  UnwrappedLineFormatter(ContinuationIndenter *Indenter,                           WhitespaceManager *Whitespaces,                           const FormatStyle &Style) -      : SourceMgr(SourceMgr), Ranges(Ranges), Indenter(Indenter), -        Whitespaces(Whitespaces), Style(Style), Joiner(Style) {} +      : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style), +        Joiner(Style) {}    unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun, -                  int AdditionalIndent = 0) { +                  int AdditionalIndent = 0, bool FixBadIndentation = false) { +    // Try to look up already computed penalty in DryRun-mode. +    std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey( +        &Lines, AdditionalIndent); +    auto CacheIt = PenaltyCache.find(CacheKey); +    if (DryRun && CacheIt != PenaltyCache.end()) +      return CacheIt->second; +      assert(!Lines.empty());      unsigned Penalty = 0;      std::vector<int> IndentForLevel;      for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)        IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent); -    bool PreviousLineWasTouched = false; -    const AnnotatedLine *PreviousLine = NULL; -    bool FormatPPDirective = false; +    const AnnotatedLine *PreviousLine = nullptr;      for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),                                                            E = Lines.end();           I != E; ++I) { @@ -551,21 +818,30 @@ public:        const FormatToken *FirstTok = TheLine.First;        int Offset = getIndentOffset(*FirstTok); -      // Check whether this line is part of a formatted preprocessor directive. -      if (FirstTok->HasUnescapedNewline) -        FormatPPDirective = false; -      if (!FormatPPDirective && TheLine.InPPDirective && -          (touchesLine(TheLine) || touchesPPDirective(I + 1, E))) -        FormatPPDirective = true; -        // Determine indent and try to merge multiple unwrapped lines. -      while (IndentForLevel.size() <= TheLine.Level) -        IndentForLevel.push_back(-1); -      IndentForLevel.resize(TheLine.Level + 1); -      unsigned Indent = getIndent(IndentForLevel, TheLine.Level); +      unsigned Indent; +      if (TheLine.InPPDirective) { +        Indent = TheLine.Level * Style.IndentWidth; +      } else { +        while (IndentForLevel.size() <= TheLine.Level) +          IndentForLevel.push_back(-1); +        IndentForLevel.resize(TheLine.Level + 1); +        Indent = getIndent(IndentForLevel, TheLine.Level); +      } +      unsigned LevelIndent = Indent;        if (static_cast<int>(Indent) + Offset >= 0)          Indent += Offset; + +      // Merge multiple lines if possible.        unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E); +      if (MergedLines > 0 && Style.ColumnLimit == 0) { +        // Disallow line merging if there is a break at the start of one of the +        // input lines. +        for (unsigned i = 0; i < MergedLines; ++i) { +          if (I[i + 1]->First->NewlinesBefore > 0) +            MergedLines = 0; +        } +      }        if (!DryRun) {          for (unsigned i = 0; i < MergedLines; ++i) {            join(*I[i], *I[i + 1]); @@ -573,18 +849,18 @@ public:        }        I += MergedLines; -      bool WasMoved = PreviousLineWasTouched && FirstTok->NewlinesBefore == 0; +      bool FixIndentation = +          FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);        if (TheLine.First->is(tok::eof)) { -        if (PreviousLineWasTouched && !DryRun) { +        if (PreviousLine && PreviousLine->Affected && !DryRun) { +          // Remove the file's trailing whitespace.            unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);            Whitespaces->replaceWhitespace(*TheLine.First, Newlines,                                           /*IndentLevel=*/0, /*Spaces=*/0,                                           /*TargetColumn=*/0);          }        } else if (TheLine.Type != LT_Invalid && -                 (WasMoved || FormatPPDirective || touchesLine(TheLine))) { -        unsigned LevelIndent = -            getIndent(IndentForLevel, TheLine.Level); +                 (TheLine.Affected || FixIndentation)) {          if (FirstTok->WhitespaceRange.isValid()) {            if (!DryRun)              formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, @@ -603,9 +879,12 @@ public:          if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {            LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun); -          while (State.NextToken != NULL) +          while (State.NextToken) { +            formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);              Indenter->addTokenToState(State, /*Newline=*/false, DryRun); +          }          } else if (Style.ColumnLimit == 0) { +          // FIXME: Implement nested blocks for ColumnLimit = 0.            NoColumnLimitFormatter Formatter(Indenter);            if (!DryRun)              Formatter.format(Indent, &TheLine); @@ -613,19 +892,21 @@ public:            Penalty += format(TheLine, Indent, DryRun);          } -        IndentForLevel[TheLine.Level] = LevelIndent; -        PreviousLineWasTouched = true; +        if (!TheLine.InPPDirective) +          IndentForLevel[TheLine.Level] = LevelIndent; +      } else if (TheLine.ChildrenAffected) { +        format(TheLine.Children, DryRun);        } else {          // Format the first token if necessary, and notify the WhitespaceManager          // about the unchanged whitespace. -        for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) { +        for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {            if (Tok == TheLine.First &&                (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {              unsigned LevelIndent = Tok->OriginalColumn;              if (!DryRun) { -              // Remove trailing whitespace of the previous line if it was -              // touched. -              if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) { +              // Remove trailing whitespace of the previous line. +              if ((PreviousLine && PreviousLine->Affected) || +                  TheLine.LeadingEmptyLinesAffected) {                  formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,                                   TheLine.InPPDirective);                } else { @@ -635,24 +916,21 @@ public:              if (static_cast<int>(LevelIndent) - Offset >= 0)                LevelIndent -= Offset; -            if (Tok->isNot(tok::comment)) +            if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)                IndentForLevel[TheLine.Level] = LevelIndent;            } else if (!DryRun) {              Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);            }          } -        // If we did not reformat this unwrapped line, the column at the end of -        // the last token is unchanged - thus, we can calculate the end of the -        // last token. -        PreviousLineWasTouched = false;        }        if (!DryRun) { -        for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) { +        for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {            Tok->Finalized = true;          }        }        PreviousLine = *I;      } +    PenaltyCache[CacheKey] = Penalty;      return Penalty;    } @@ -722,6 +1000,14 @@ private:        Newlines = std::min(Newlines, 1u);      if (Newlines == 0 && !RootToken.IsFirst)        Newlines = 1; +    if (RootToken.IsFirst && !RootToken.HasUnescapedNewline) +      Newlines = 0; + +    // Remove empty lines after "{". +    if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine && +        PreviousLine->Last->is(tok::l_brace) && +        PreviousLine->First->isNot(tok::kw_namespace)) +      Newlines = 1;      // Insert extra new line before access specifiers.      if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) && @@ -732,9 +1018,9 @@ private:      if (PreviousLine && PreviousLine->First->isAccessSpecifier())        Newlines = std::min(1u, Newlines); -    Whitespaces->replaceWhitespace( -        RootToken, Newlines, IndentLevel, Indent, Indent, -        InPPDirective && !RootToken.HasUnescapedNewline); +    Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent, +                                   Indent, InPPDirective && +                                               !RootToken.HasUnescapedNewline);    }    /// \brief Get the indent of \p Level from \p IndentForLevel. @@ -753,6 +1039,8 @@ private:    void join(AnnotatedLine &A, const AnnotatedLine &B) {      assert(!A.Last->Next);      assert(!B.First->Previous); +    if (B.Affected) +      A.Affected = true;      A.Last->Next = B.First;      B.First->Previous = A.Last;      B.First->CanBreakBefore = true; @@ -768,47 +1056,11 @@ private:      return Style.ColumnLimit - (InPPDirective ? 2 : 0);    } -  bool touchesRanges(const CharSourceRange &Range) { -    for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), -                                                          E = Ranges.end(); -         I != E; ++I) { -      if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) && -          !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin())) -        return true; -    } -    return false; -  } - -  bool touchesLine(const AnnotatedLine &TheLine) { -    const FormatToken *First = TheLine.First; -    const FormatToken *Last = TheLine.Last; -    CharSourceRange LineRange = CharSourceRange::getCharRange( -        First->WhitespaceRange.getBegin().getLocWithOffset( -            First->LastNewlineOffset), -        Last->getStartOfNonWhitespace().getLocWithOffset( -            Last->TokenText.size() - 1)); -    return touchesRanges(LineRange); -  } - -  bool touchesPPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I, -                          SmallVectorImpl<AnnotatedLine *>::const_iterator E) { -    for (; I != E; ++I) { -      if ((*I)->First->HasUnescapedNewline) -        return false; -      if (touchesLine(**I)) -        return true; +  struct CompareLineStatePointers { +    bool operator()(LineState *obj1, LineState *obj2) const { +      return *obj1 < *obj2;      } -    return false; -  } - -  bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) { -    const FormatToken *First = TheLine.First; -    CharSourceRange LineRange = CharSourceRange::getCharRange( -        First->WhitespaceRange.getBegin(), -        First->WhitespaceRange.getBegin().getLocWithOffset( -            First->LastNewlineOffset)); -    return touchesRanges(LineRange); -  } +  };    /// \brief Analyze the entire solution space starting from \p InitialState.    /// @@ -819,7 +1071,7 @@ private:    ///    /// If \p DryRun is \c false, directly applies the changes.    unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) { -    std::set<LineState> Seen; +    std::set<LineState *, CompareLineStatePointers> Seen;      // Increasing count of \c StateNode items we have created. This is used to      // create a deterministic order independent of the container. @@ -828,7 +1080,7 @@ private:      // Insert start element into queue.      StateNode *Node = -        new (Allocator.Allocate()) StateNode(InitialState, false, NULL); +        new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);      Queue.push(QueueItem(OrderedPenalty(0, Count), Node));      ++Count; @@ -838,7 +1090,7 @@ private:      while (!Queue.empty()) {        Penalty = Queue.top().first.first;        StateNode *Node = Queue.top().second; -      if (Node->State.NextToken == NULL) { +      if (!Node->State.NextToken) {          DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");          break;        } @@ -849,7 +1101,7 @@ private:        if (Count > 10000)          Node->State.IgnoreStackForComparison = true; -      if (!Seen.insert(Node->State).second) +      if (!Seen.insert(&Node->State).second)          // State already examined with lower penalty.          continue; @@ -953,20 +1205,38 @@ private:        return true;      if (NewLine) { -      int AdditionalIndent = State.Stack.back().Indent - -                             Previous.Children[0]->Level * Style.IndentWidth; -      Penalty += format(Previous.Children, DryRun, AdditionalIndent); +      int AdditionalIndent = +          State.FirstIndent - State.Line->Level * Style.IndentWidth; +      if (State.Stack.size() < 2 || +          !State.Stack[State.Stack.size() - 2].JSFunctionInlined) { +        AdditionalIndent = State.Stack.back().Indent - +                           Previous.Children[0]->Level * Style.IndentWidth; +      } + +      Penalty += format(Previous.Children, DryRun, AdditionalIndent, +                        /*FixBadIndentation=*/true);        return true;      }      // Cannot merge multiple statements into a single line.      if (Previous.Children.size() > 1) -      return false;  +      return false; + +    // Cannot merge into one line if this line ends on a comment. +    if (Previous.is(tok::comment)) +      return false;      // We can't put the closing "}" on a line with a trailing comment.      if (Previous.Children[0]->Last->isTrailingComment())        return false; +    // If the child line exceeds the column limit, we wouldn't want to merge it. +    // We add +2 for the trailing " }". +    if (Style.ColumnLimit > 0 && +        Previous.Children[0]->Last->TotalLength + State.Column + 2 > +            Style.ColumnLimit) +      return false; +      if (!DryRun) {        Whitespaces->replaceWhitespace(            *Previous.Children[0]->First, @@ -979,31 +1249,43 @@ private:      return true;    } -  SourceManager &SourceMgr; -  SmallVectorImpl<CharSourceRange> &Ranges;    ContinuationIndenter *Indenter;    WhitespaceManager *Whitespaces;    FormatStyle Style;    LineJoiner Joiner;    llvm::SpecificBumpPtrAllocator<StateNode> Allocator; + +  // Cache to store the penalty of formatting a vector of AnnotatedLines +  // starting from a specific additional offset. Improves performance if there +  // are many nested blocks. +  std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>, +           unsigned> PenaltyCache;  };  class FormatTokenLexer {  public:    FormatTokenLexer(Lexer &Lex, SourceManager &SourceMgr, FormatStyle &Style,                     encoding::Encoding Encoding) -      : FormatTok(NULL), IsFirstToken(true), GreaterStashed(false), Column(0), -        TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style), -        IdentTable(getFormattingLangOpts()), Encoding(Encoding) { +      : FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), +        Column(0), TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), +        Style(Style), IdentTable(getFormattingLangOpts()), Encoding(Encoding), +        FirstInLineIndex(0) {      Lex.SetKeepWhitespaceMode(true); + +    for (const std::string &ForEachMacro : Style.ForEachMacros) +      ForEachMacros.push_back(&IdentTable.get(ForEachMacro)); +    std::sort(ForEachMacros.begin(), ForEachMacros.end());    }    ArrayRef<FormatToken *> lex() {      assert(Tokens.empty()); +    assert(FirstInLineIndex == 0);      do {        Tokens.push_back(getNextToken()); -      maybeJoinPreviousTokens(); +      tryMergePreviousTokens(); +      if (Tokens.back()->NewlinesBefore > 0) +        FirstInLineIndex = Tokens.size() - 1;      } while (Tokens.back()->Tok.isNot(tok::eof));      return Tokens;    } @@ -1011,23 +1293,125 @@ public:    IdentifierTable &getIdentTable() { return IdentTable; }  private: -  void maybeJoinPreviousTokens() { -    if (Tokens.size() < 4) +  void tryMergePreviousTokens() { +    if (tryMerge_TMacro())        return; +    if (tryMergeConflictMarkers()) +      return; + +    if (Style.Language == FormatStyle::LK_JavaScript) { +      if (tryMergeEscapeSequence()) +        return; +      if (tryMergeJSRegexLiteral()) +        return; + +      static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal }; +      static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal }; +      static tok::TokenKind JSShiftEqual[] = { tok::greater, tok::greater, +                                               tok::greaterequal }; +      static tok::TokenKind JSRightArrow[] = { tok::equal, tok::greater }; +      // FIXME: We probably need to change token type to mimic operator with the +      // correct priority. +      if (tryMergeTokens(JSIdentity)) +        return; +      if (tryMergeTokens(JSNotIdentity)) +        return; +      if (tryMergeTokens(JSShiftEqual)) +        return; +      if (tryMergeTokens(JSRightArrow)) +        return; +    } +  } + +  bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds) { +    if (Tokens.size() < Kinds.size()) +      return false; + +    SmallVectorImpl<FormatToken *>::const_iterator First = +        Tokens.end() - Kinds.size(); +    if (!First[0]->is(Kinds[0])) +      return false; +    unsigned AddLength = 0; +    for (unsigned i = 1; i < Kinds.size(); ++i) { +      if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() != +                                         First[i]->WhitespaceRange.getEnd()) +        return false; +      AddLength += First[i]->TokenText.size(); +    } +    Tokens.resize(Tokens.size() - Kinds.size() + 1); +    First[0]->TokenText = StringRef(First[0]->TokenText.data(), +                                    First[0]->TokenText.size() + AddLength); +    First[0]->ColumnWidth += AddLength; +    return true; +  } + +  // Tries to merge an escape sequence, i.e. a "\\" and the following +  // character. Use e.g. inside JavaScript regex literals. +  bool tryMergeEscapeSequence() { +    if (Tokens.size() < 2) +      return false; +    FormatToken *Previous = Tokens[Tokens.size() - 2]; +    if (Previous->isNot(tok::unknown) || Previous->TokenText != "\\" || +        Tokens.back()->NewlinesBefore != 0) +      return false; +    Previous->ColumnWidth += Tokens.back()->ColumnWidth; +    StringRef Text = Previous->TokenText; +    Previous->TokenText = +        StringRef(Text.data(), Text.size() + Tokens.back()->TokenText.size()); +    Tokens.resize(Tokens.size() - 1); +    return true; +  } + +  // Try to determine whether the current token ends a JavaScript regex literal. +  // We heuristically assume that this is a regex literal if we find two +  // unescaped slashes on a line and the token before the first slash is one of +  // "(;,{}![:?", a binary operator or 'return', as those cannot be followed by +  // a division. +  bool tryMergeJSRegexLiteral() { +    if (Tokens.size() < 2 || Tokens.back()->isNot(tok::slash) || +        (Tokens[Tokens.size() - 2]->is(tok::unknown) && +         Tokens[Tokens.size() - 2]->TokenText == "\\")) +      return false; +    unsigned TokenCount = 0; +    unsigned LastColumn = Tokens.back()->OriginalColumn; +    for (auto I = Tokens.rbegin() + 1, E = Tokens.rend(); I != E; ++I) { +      ++TokenCount; +      if (I[0]->is(tok::slash) && I + 1 != E && +          (I[1]->isOneOf(tok::l_paren, tok::semi, tok::l_brace, tok::r_brace, +                         tok::exclaim, tok::l_square, tok::colon, tok::comma, +                         tok::question, tok::kw_return) || +           I[1]->isBinaryOperator())) { +        Tokens.resize(Tokens.size() - TokenCount); +        Tokens.back()->Tok.setKind(tok::unknown); +        Tokens.back()->Type = TT_RegexLiteral; +        Tokens.back()->ColumnWidth += LastColumn - I[0]->OriginalColumn; +        return true; +      } + +      // There can't be a newline inside a regex literal. +      if (I[0]->NewlinesBefore > 0) +        return false; +    } +    return false; +  } + +  bool tryMerge_TMacro() { +    if (Tokens.size() < 4) +      return false;      FormatToken *Last = Tokens.back();      if (!Last->is(tok::r_paren)) -      return; +      return false;      FormatToken *String = Tokens[Tokens.size() - 2];      if (!String->is(tok::string_literal) || String->IsMultiline) -      return; +      return false;      if (!Tokens[Tokens.size() - 3]->is(tok::l_paren)) -      return; +      return false;      FormatToken *Macro = Tokens[Tokens.size() - 4];      if (Macro->TokenText != "_T") -      return; +      return false;      const char *Start = Macro->TokenText.data();      const char *End = Last->TokenText.data() + Last->TokenText.size(); @@ -1043,6 +1427,69 @@ private:      Tokens.pop_back();      Tokens.pop_back();      Tokens.back() = String; +    return true; +  } + +  bool tryMergeConflictMarkers() { +    if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof)) +      return false; + +    // Conflict lines look like: +    // <marker> <text from the vcs> +    // For example: +    // >>>>>>> /file/in/file/system at revision 1234 +    // +    // We merge all tokens in a line that starts with a conflict marker +    // into a single token with a special token type that the unwrapped line +    // parser will use to correctly rebuild the underlying code. + +    FileID ID; +    // Get the position of the first token in the line. +    unsigned FirstInLineOffset; +    std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc( +        Tokens[FirstInLineIndex]->getStartOfNonWhitespace()); +    StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer(); +    // Calculate the offset of the start of the current line. +    auto LineOffset = Buffer.rfind('\n', FirstInLineOffset); +    if (LineOffset == StringRef::npos) { +      LineOffset = 0; +    } else { +      ++LineOffset; +    } + +    auto FirstSpace = Buffer.find_first_of(" \n", LineOffset); +    StringRef LineStart; +    if (FirstSpace == StringRef::npos) { +      LineStart = Buffer.substr(LineOffset); +    } else { +      LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset); +    } + +    TokenType Type = TT_Unknown; +    if (LineStart == "<<<<<<<" || LineStart == ">>>>") { +      Type = TT_ConflictStart; +    } else if (LineStart == "|||||||" || LineStart == "=======" || +               LineStart == "====") { +      Type = TT_ConflictAlternative; +    } else if (LineStart == ">>>>>>>" || LineStart == "<<<<") { +      Type = TT_ConflictEnd; +    } + +    if (Type != TT_Unknown) { +      FormatToken *Next = Tokens.back(); + +      Tokens.resize(FirstInLineIndex + 1); +      // We do not need to build a complete token here, as we will skip it +      // during parsing anyway (as we must not touch whitespace around conflict +      // markers). +      Tokens.back()->Type = Type; +      Tokens.back()->Tok.setKind(tok::kw___unknown_anytype); + +      Tokens.push_back(Next); +      return true; +    } + +    return false;    }    FormatToken *getNextToken() { @@ -1122,7 +1569,7 @@ private:      // FIXME: Add a more explicit test.      while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&             FormatTok->TokenText[1] == '\n') { -      // FIXME: ++FormatTok->NewlinesBefore is missing... +      ++FormatTok->NewlinesBefore;        WhitespaceLength += 2;        Column = 0;        FormatTok->TokenText = FormatTok->TokenText.substr(2); @@ -1174,6 +1621,10 @@ private:        Column = FormatTok->LastLineColumnWidth;      } +    FormatTok->IsForEachMacro = +        std::binary_search(ForEachMacros.begin(), ForEachMacros.end(), +                           FormatTok->Tok.getIdentifierInfo()); +      return FormatTok;    } @@ -1188,7 +1639,10 @@ private:    IdentifierTable IdentTable;    encoding::Encoding Encoding;    llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; +  // Index (in 'Tokens') of the last token that starts a new line. +  unsigned FirstInLineIndex;    SmallVector<FormatToken *, 16> Tokens; +  SmallVector<IdentifierInfo *, 8> ForEachMacros;    void readRawToken(FormatToken &Tok) {      Lex.LexFromRawLexer(Tok.Tok); @@ -1196,14 +1650,31 @@ private:                                Tok.Tok.getLength());      // For formatting, treat unterminated string literals like normal string      // literals. -    if (Tok.is(tok::unknown) && !Tok.TokenText.empty() && -        Tok.TokenText[0] == '"') { -      Tok.Tok.setKind(tok::string_literal); -      Tok.IsUnterminatedLiteral = true; +    if (Tok.is(tok::unknown)) { +      if (!Tok.TokenText.empty() && Tok.TokenText[0] == '"') { +        Tok.Tok.setKind(tok::string_literal); +        Tok.IsUnterminatedLiteral = true; +      } else if (Style.Language == FormatStyle::LK_JavaScript && +                 Tok.TokenText == "''") { +        Tok.Tok.setKind(tok::char_constant); +      }      }    }  }; +static StringRef getLanguageName(FormatStyle::LanguageKind Language) { +  switch (Language) { +  case FormatStyle::LK_Cpp: +    return "C++"; +  case FormatStyle::LK_JavaScript: +    return "JavaScript"; +  case FormatStyle::LK_Proto: +    return "Proto"; +  default: +    return "Unknown"; +  } +} +  class Formatter : public UnwrappedLineConsumer {  public:    Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, @@ -1216,6 +1687,8 @@ public:                         << (Encoding == encoding::Encoding_UTF8 ? "UTF8"                                                                 : "unknown")                         << "\n"); +    DEBUG(llvm::dbgs() << "Language: " << getLanguageName(Style.Language) +                       << "\n");    }    tooling::Replacements format() { @@ -1261,17 +1734,151 @@ public:      for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {        Annotator.calculateFormattingInformation(*AnnotatedLines[i]);      } +    computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());      Annotator.setCommentLineLevels(AnnotatedLines);      ContinuationIndenter Indenter(Style, SourceMgr, Whitespaces, Encoding,                                    BinPackInconclusiveFunctions); -    UnwrappedLineFormatter Formatter(SourceMgr, Ranges, &Indenter, &Whitespaces, -                                     Style); +    UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);      Formatter.format(AnnotatedLines, /*DryRun=*/false);      return Whitespaces.generateReplacements();    }  private: +  // Determines which lines are affected by the SourceRanges given as input. +  // Returns \c true if at least one line between I and E or one of their +  // children is affected. +  bool computeAffectedLines(SmallVectorImpl<AnnotatedLine *>::iterator I, +                            SmallVectorImpl<AnnotatedLine *>::iterator E) { +    bool SomeLineAffected = false; +    const AnnotatedLine *PreviousLine = nullptr; +    while (I != E) { +      AnnotatedLine *Line = *I; +      Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First); + +      // If a line is part of a preprocessor directive, it needs to be formatted +      // if any token within the directive is affected. +      if (Line->InPPDirective) { +        FormatToken *Last = Line->Last; +        SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1; +        while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) { +          Last = (*PPEnd)->Last; +          ++PPEnd; +        } + +        if (affectsTokenRange(*Line->First, *Last, +                              /*IncludeLeadingNewlines=*/false)) { +          SomeLineAffected = true; +          markAllAsAffected(I, PPEnd); +        } +        I = PPEnd; +        continue; +      } + +      if (nonPPLineAffected(Line, PreviousLine)) +        SomeLineAffected = true; + +      PreviousLine = Line; +      ++I; +    } +    return SomeLineAffected; +  } + +  // Determines whether 'Line' is affected by the SourceRanges given as input. +  // Returns \c true if line or one if its children is affected. +  bool nonPPLineAffected(AnnotatedLine *Line, +                         const AnnotatedLine *PreviousLine) { +    bool SomeLineAffected = false; +    Line->ChildrenAffected = +        computeAffectedLines(Line->Children.begin(), Line->Children.end()); +    if (Line->ChildrenAffected) +      SomeLineAffected = true; + +    // Stores whether one of the line's tokens is directly affected. +    bool SomeTokenAffected = false; +    // Stores whether we need to look at the leading newlines of the next token +    // in order to determine whether it was affected. +    bool IncludeLeadingNewlines = false; + +    // Stores whether the first child line of any of this line's tokens is +    // affected. +    bool SomeFirstChildAffected = false; + +    for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) { +      // Determine whether 'Tok' was affected. +      if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines)) +        SomeTokenAffected = true; + +      // Determine whether the first child of 'Tok' was affected. +      if (!Tok->Children.empty() && Tok->Children.front()->Affected) +        SomeFirstChildAffected = true; + +      IncludeLeadingNewlines = Tok->Children.empty(); +    } + +    // Was this line moved, i.e. has it previously been on the same line as an +    // affected line? +    bool LineMoved = PreviousLine && PreviousLine->Affected && +                     Line->First->NewlinesBefore == 0; + +    bool IsContinuedComment = +        Line->First->is(tok::comment) && Line->First->Next == nullptr && +        Line->First->NewlinesBefore < 2 && PreviousLine && +        PreviousLine->Affected && PreviousLine->Last->is(tok::comment); + +    if (SomeTokenAffected || SomeFirstChildAffected || LineMoved || +        IsContinuedComment) { +      Line->Affected = true; +      SomeLineAffected = true; +    } +    return SomeLineAffected; +  } + +  // Marks all lines between I and E as well as all their children as affected. +  void markAllAsAffected(SmallVectorImpl<AnnotatedLine *>::iterator I, +                         SmallVectorImpl<AnnotatedLine *>::iterator E) { +    while (I != E) { +      (*I)->Affected = true; +      markAllAsAffected((*I)->Children.begin(), (*I)->Children.end()); +      ++I; +    } +  } + +  // Returns true if the range from 'First' to 'Last' intersects with one of the +  // input ranges. +  bool affectsTokenRange(const FormatToken &First, const FormatToken &Last, +                         bool IncludeLeadingNewlines) { +    SourceLocation Start = First.WhitespaceRange.getBegin(); +    if (!IncludeLeadingNewlines) +      Start = Start.getLocWithOffset(First.LastNewlineOffset); +    SourceLocation End = Last.getStartOfNonWhitespace(); +    if (Last.TokenText.size() > 0) +      End = End.getLocWithOffset(Last.TokenText.size() - 1); +    CharSourceRange Range = CharSourceRange::getCharRange(Start, End); +    return affectsCharSourceRange(Range); +  } + +  // Returns true if one of the input ranges intersect the leading empty lines +  // before 'Tok'. +  bool affectsLeadingEmptyLines(const FormatToken &Tok) { +    CharSourceRange EmptyLineRange = CharSourceRange::getCharRange( +        Tok.WhitespaceRange.getBegin(), +        Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset)); +    return affectsCharSourceRange(EmptyLineRange); +  } + +  // Returns true if 'Range' intersects with one of the input ranges. +  bool affectsCharSourceRange(const CharSourceRange &Range) { +    for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), +                                                          E = Ranges.end(); +         I != E; ++I) { +      if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) && +          !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin())) +        return true; +    } +    return false; +  } +    static bool inputUsesCRLF(StringRef Text) {      return Text.count('\r') * 2 > Text.count('\n');    } @@ -1316,11 +1923,11 @@ private:          Tok = Tok->Next;        }      } -    if (Style.DerivePointerBinding) { +    if (Style.DerivePointerAlignment) {        if (CountBoundToType > CountBoundToVariable) -        Style.PointerBindsToType = true; +        Style.PointerAlignment = FormatStyle::PAS_Left;        else if (CountBoundToType < CountBoundToVariable) -        Style.PointerBindsToType = false; +        Style.PointerAlignment = FormatStyle::PAS_Right;      }      if (Style.Standard == FormatStyle::LS_Auto) {        Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11 @@ -1330,12 +1937,12 @@ private:          HasBinPackedFunction || !HasOnePerLineFunction;    } -  virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) { +  void consumeUnwrappedLine(const UnwrappedLine &TheLine) override {      assert(!UnwrappedLines.empty());      UnwrappedLines.back().push_back(TheLine);    } -  virtual void finishRun() { +  void finishRun() override {      UnwrappedLines.push_back(SmallVector<UnwrappedLine, 16>());    } @@ -1355,6 +1962,11 @@ private:  tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,                                 SourceManager &SourceMgr,                                 std::vector<CharSourceRange> Ranges) { +  if (Style.DisableFormat) { +    tooling::Replacements EmptyResult; +    return EmptyResult; +  } +    Formatter formatter(Style, Lex, SourceMgr, Ranges);    return formatter.format();  } @@ -1389,7 +2001,9 @@ LangOptions getFormattingLangOpts(FormatStyle::LanguageStandard Standard) {    LangOptions LangOpts;    LangOpts.CPlusPlus = 1;    LangOpts.CPlusPlus11 = Standard == FormatStyle::LS_Cpp03 ? 0 : 1; +  LangOpts.CPlusPlus1y = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;    LangOpts.LineComment = 1; +  LangOpts.CXXOperatorNames = 1;    LangOpts.Bool = 1;    LangOpts.ObjC1 = 1;    LangOpts.ObjC2 = 1; @@ -1407,15 +2021,29 @@ const char *StyleOptionHelpDescription =      "parameters, e.g.:\n"      "  -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\""; -FormatStyle getStyle(StringRef StyleName, StringRef FileName) { -  // Fallback style in case the rest of this function can't determine a style. -  StringRef FallbackStyle = "LLVM"; -  FormatStyle Style; -  getPredefinedStyle(FallbackStyle, &Style); +static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { +  if (FileName.endswith_lower(".js")) { +    return FormatStyle::LK_JavaScript; +  } else if (FileName.endswith_lower(".proto") || +             FileName.endswith_lower(".protodevel")) { +    return FormatStyle::LK_Proto; +  } +  return FormatStyle::LK_Cpp; +} + +FormatStyle getStyle(StringRef StyleName, StringRef FileName, +                     StringRef FallbackStyle) { +  FormatStyle Style = getLLVMStyle(); +  Style.Language = getLanguageByFileName(FileName); +  if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) { +    llvm::errs() << "Invalid fallback style \"" << FallbackStyle +                 << "\" using LLVM style\n"; +    return Style; +  }    if (StyleName.startswith("{")) {      // Parse YAML/JSON style from the command line. -    if (llvm::error_code ec = parseConfiguration(StyleName, &Style)) { +    if (std::error_code ec = parseConfiguration(StyleName, &Style)) {        llvm::errs() << "Error parsing -style: " << ec.message() << ", using "                     << FallbackStyle << " style\n";      } @@ -1423,12 +2051,14 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {    }    if (!StyleName.equals_lower("file")) { -    if (!getPredefinedStyle(StyleName, &Style)) +    if (!getPredefinedStyle(StyleName, Style.Language, &Style))        llvm::errs() << "Invalid value for -style, using " << FallbackStyle                     << " style\n";      return Style;    } +  // Look for .clang-format/_clang-format file in the file's parent directories. +  SmallString<128> UnsuitableConfigFiles;    SmallString<128> Path(FileName);    llvm::sys::fs::make_absolute(Path);    for (StringRef Directory = Path; !Directory.empty(); @@ -1453,16 +2083,23 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {      }      if (IsFile) { -      OwningPtr<llvm::MemoryBuffer> Text; -      if (llvm::error_code ec = -              llvm::MemoryBuffer::getFile(ConfigFile.c_str(), Text)) { -        llvm::errs() << ec.message() << "\n"; -        continue; +      llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = +          llvm::MemoryBuffer::getFile(ConfigFile.c_str()); +      if (std::error_code EC = Text.getError()) { +        llvm::errs() << EC.message() << "\n"; +        break;        } -      if (llvm::error_code ec = parseConfiguration(Text->getBuffer(), &Style)) { +      if (std::error_code ec = +              parseConfiguration(Text.get()->getBuffer(), &Style)) { +        if (ec == ParseError::Unsuitable) { +          if (!UnsuitableConfigFiles.empty()) +            UnsuitableConfigFiles.append(", "); +          UnsuitableConfigFiles.append(ConfigFile); +          continue; +        }          llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()                       << "\n"; -        continue; +        break;        }        DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");        return Style; @@ -1470,6 +2107,11 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {    }    llvm::errs() << "Can't find usable .clang-format, using " << FallbackStyle                 << " style\n"; +  if (!UnsuitableConfigFiles.empty()) { +    llvm::errs() << "Configuration file(s) do(es) not support " +                 << getLanguageName(Style.Language) << ": " +                 << UnsuitableConfigFiles << "\n"; +  }    return Style;  } | 
