diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 | 
| commit | 45b533945f0851ec234ca846e1af5ee1e4df0b6e (patch) | |
| tree | 0a5b74c0b9ca73aded34df95c91fcaf3815230d8 /lib/Format/Format.cpp | |
| parent | 7e86edd64bfae4e324224452e4ea879b3371a4bd (diff) | |
Notes
Diffstat (limited to 'lib/Format/Format.cpp')
| -rw-r--r-- | lib/Format/Format.cpp | 616 | 
1 files changed, 467 insertions, 149 deletions
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 382ae819ebfd..5068fca5c44d 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -13,6 +13,7 @@  ///  //===----------------------------------------------------------------------===// +#include "clang/Format/Format.h"  #include "ContinuationIndenter.h"  #include "TokenAnnotator.h"  #include "UnwrappedLineFormatter.h" @@ -21,7 +22,6 @@  #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" @@ -37,6 +37,7 @@  using clang::format::FormatStyle;  LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)  namespace llvm {  namespace yaml { @@ -46,6 +47,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {      IO.enumCase(Value, "Java", FormatStyle::LK_Java);      IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);      IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); +    IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);    }  }; @@ -98,11 +100,27 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {      IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);      IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);      IO.enumCase(Value, "GNU", FormatStyle::BS_GNU); +    IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit); +    IO.enumCase(Value, "Custom", FormatStyle::BS_Custom); +  } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> { +  static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { +    IO.enumCase(Value, "None", FormatStyle::RTBS_None); +    IO.enumCase(Value, "All", FormatStyle::RTBS_All); +    IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel); +    IO.enumCase(Value, "TopLevelDefinitions", +                FormatStyle::RTBS_TopLevelDefinitions); +    IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);    }  }; -template <> struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> { -  static void enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) { +template <> +struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> { +  static void +  enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {      IO.enumCase(Value, "None", FormatStyle::DRTBS_None);      IO.enumCase(Value, "All", FormatStyle::DRTBS_All);      IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel); @@ -123,6 +141,18 @@ struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {    }  }; +template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> { +  static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) { +    IO.enumCase(Value, "Align", FormatStyle::BAS_Align); +    IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign); +    IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak); + +    // For backward compatibility. +    IO.enumCase(Value, "true", FormatStyle::BAS_Align); +    IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign); +  } +}; +  template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {    static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {      IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle); @@ -197,6 +227,8 @@ template <> struct MappingTraits<FormatStyle> {      IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);      IO.mapOptional("AlignConsecutiveAssignments",                     Style.AlignConsecutiveAssignments); +    IO.mapOptional("AlignConsecutiveDeclarations", +                   Style.AlignConsecutiveDeclarations);      IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);      IO.mapOptional("AlignOperands", Style.AlignOperands);      IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments); @@ -214,12 +246,28 @@ template <> struct MappingTraits<FormatStyle> {                     Style.AllowShortLoopsOnASingleLine);      IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",                     Style.AlwaysBreakAfterDefinitionReturnType); +    IO.mapOptional("AlwaysBreakAfterReturnType", +                   Style.AlwaysBreakAfterReturnType); +    // If AlwaysBreakAfterDefinitionReturnType was specified but +    // AlwaysBreakAfterReturnType was not, initialize the latter from the +    // former for backwards compatibility. +    if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None && +        Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) { +      if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All) +        Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; +      else if (Style.AlwaysBreakAfterDefinitionReturnType == +               FormatStyle::DRTBS_TopLevel) +        Style.AlwaysBreakAfterReturnType = +            FormatStyle::RTBS_TopLevelDefinitions; +    } +      IO.mapOptional("AlwaysBreakBeforeMultilineStrings",                     Style.AlwaysBreakBeforeMultilineStrings);      IO.mapOptional("AlwaysBreakTemplateDeclarations",                     Style.AlwaysBreakTemplateDeclarations);      IO.mapOptional("BinPackArguments", Style.BinPackArguments);      IO.mapOptional("BinPackParameters", Style.BinPackParameters); +    IO.mapOptional("BraceWrapping", Style.BraceWrapping);      IO.mapOptional("BreakBeforeBinaryOperators",                     Style.BreakBeforeBinaryOperators);      IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); @@ -240,6 +288,7 @@ template <> struct MappingTraits<FormatStyle> {      IO.mapOptional("ExperimentalAutoDetectBinPacking",                     Style.ExperimentalAutoDetectBinPacking);      IO.mapOptional("ForEachMacros", Style.ForEachMacros); +    IO.mapOptional("IncludeCategories", Style.IncludeCategories);      IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);      IO.mapOptional("IndentWidth", Style.IndentWidth);      IO.mapOptional("IndentWrappedFunctionNames", @@ -264,6 +313,8 @@ template <> struct MappingTraits<FormatStyle> {      IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",                     Style.PenaltyReturnTypeOnItsOwnLine);      IO.mapOptional("PointerAlignment", Style.PointerAlignment); +    IO.mapOptional("ReflowComments", Style.ReflowComments); +    IO.mapOptional("SortIncludes", Style.SortIncludes);      IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);      IO.mapOptional("SpaceBeforeAssignmentOperators",                     Style.SpaceBeforeAssignmentOperators); @@ -284,6 +335,29 @@ template <> struct MappingTraits<FormatStyle> {    }  }; +template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> { +  static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) { +    IO.mapOptional("AfterClass", Wrapping.AfterClass); +    IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement); +    IO.mapOptional("AfterEnum", Wrapping.AfterEnum); +    IO.mapOptional("AfterFunction", Wrapping.AfterFunction); +    IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace); +    IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration); +    IO.mapOptional("AfterStruct", Wrapping.AfterStruct); +    IO.mapOptional("AfterUnion", Wrapping.AfterUnion); +    IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); +    IO.mapOptional("BeforeElse", Wrapping.BeforeElse); +    IO.mapOptional("IndentBraces", Wrapping.IndentBraces); +  } +}; + +template <> struct MappingTraits<FormatStyle::IncludeCategory> { +  static void mapping(IO &IO, FormatStyle::IncludeCategory &Category) { +    IO.mapOptional("Regex", Category.Regex); +    IO.mapOptional("Priority", Category.Priority); +  } +}; +  // 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. @@ -309,8 +383,8 @@ template <> struct DocumentListTraits<std::vector<FormatStyle>> {      return Seq[Index];    }  }; -} -} +} // namespace yaml +} // namespace llvm  namespace clang {  namespace format { @@ -339,21 +413,71 @@ std::string ParseErrorCategory::message(int EV) const {    llvm_unreachable("unexpected parse error");  } +static FormatStyle expandPresets(const FormatStyle &Style) { +  if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) +    return Style; +  FormatStyle Expanded = Style; +  Expanded.BraceWrapping = {false, false, false, false, false, false, +                            false, false, false, false, false}; +  switch (Style.BreakBeforeBraces) { +  case FormatStyle::BS_Linux: +    Expanded.BraceWrapping.AfterClass = true; +    Expanded.BraceWrapping.AfterFunction = true; +    Expanded.BraceWrapping.AfterNamespace = true; +    break; +  case FormatStyle::BS_Mozilla: +    Expanded.BraceWrapping.AfterClass = true; +    Expanded.BraceWrapping.AfterEnum = true; +    Expanded.BraceWrapping.AfterFunction = true; +    Expanded.BraceWrapping.AfterStruct = true; +    Expanded.BraceWrapping.AfterUnion = true; +    break; +  case FormatStyle::BS_Stroustrup: +    Expanded.BraceWrapping.AfterFunction = true; +    Expanded.BraceWrapping.BeforeCatch = true; +    Expanded.BraceWrapping.BeforeElse = true; +    break; +  case FormatStyle::BS_Allman: +    Expanded.BraceWrapping.AfterClass = true; +    Expanded.BraceWrapping.AfterControlStatement = true; +    Expanded.BraceWrapping.AfterEnum = true; +    Expanded.BraceWrapping.AfterFunction = true; +    Expanded.BraceWrapping.AfterNamespace = true; +    Expanded.BraceWrapping.AfterObjCDeclaration = true; +    Expanded.BraceWrapping.AfterStruct = true; +    Expanded.BraceWrapping.BeforeCatch = true; +    Expanded.BraceWrapping.BeforeElse = true; +    break; +  case FormatStyle::BS_GNU: +    Expanded.BraceWrapping = {true, true, true, true, true, true, +                              true, true, true, true, true}; +    break; +  case FormatStyle::BS_WebKit: +    Expanded.BraceWrapping.AfterFunction = true; +    break; +  default: +    break; +  } +  return Expanded; +} +  FormatStyle getLLVMStyle() {    FormatStyle LLVMStyle;    LLVMStyle.Language = FormatStyle::LK_Cpp;    LLVMStyle.AccessModifierOffset = -2;    LLVMStyle.AlignEscapedNewlinesLeft = false; -  LLVMStyle.AlignAfterOpenBracket = true; +  LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;    LLVMStyle.AlignOperands = true;    LLVMStyle.AlignTrailingComments = true;    LLVMStyle.AlignConsecutiveAssignments = false; +  LLVMStyle.AlignConsecutiveDeclarations = false;    LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;    LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;    LLVMStyle.AllowShortBlocksOnASingleLine = false;    LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;    LLVMStyle.AllowShortIfStatementsOnASingleLine = false;    LLVMStyle.AllowShortLoopsOnASingleLine = false; +  LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;    LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;    LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;    LLVMStyle.AlwaysBreakTemplateDeclarations = false; @@ -362,7 +486,10 @@ FormatStyle getLLVMStyle() {    LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;    LLVMStyle.BreakBeforeTernaryOperators = true;    LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; +  LLVMStyle.BraceWrapping = {false, false, false, false, false, false, +                             false, false, false, false, false};    LLVMStyle.BreakConstructorInitializersBeforeComma = false; +  LLVMStyle.BreakAfterJavaFieldAnnotations = false;    LLVMStyle.ColumnLimit = 80;    LLVMStyle.CommentPragmas = "^ IWYU pragma:";    LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; @@ -374,6 +501,9 @@ FormatStyle getLLVMStyle() {    LLVMStyle.ForEachMacros.push_back("foreach");    LLVMStyle.ForEachMacros.push_back("Q_FOREACH");    LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); +  LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2}, +                                 {"^(<|\"(gtest|isl|json)/)", 3}, +                                 {".*", 1}};    LLVMStyle.IndentCaseLabels = false;    LLVMStyle.IndentWrappedFunctionNames = false;    LLVMStyle.IndentWidth = 2; @@ -388,6 +518,7 @@ FormatStyle getLLVMStyle() {    LLVMStyle.SpacesBeforeTrailingComments = 1;    LLVMStyle.Standard = FormatStyle::LS_Cpp11;    LLVMStyle.UseTab = FormatStyle::UT_Never; +  LLVMStyle.ReflowComments = true;    LLVMStyle.SpacesInParentheses = false;    LLVMStyle.SpacesInSquareBrackets = false;    LLVMStyle.SpaceInEmptyParentheses = false; @@ -406,6 +537,7 @@ FormatStyle getLLVMStyle() {    LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;    LLVMStyle.DisableFormat = false; +  LLVMStyle.SortIncludes = true;    return LLVMStyle;  } @@ -422,6 +554,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {    GoogleStyle.AlwaysBreakTemplateDeclarations = true;    GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;    GoogleStyle.DerivePointerAlignment = true; +  GoogleStyle.IncludeCategories = {{"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};    GoogleStyle.IndentCaseLabels = true;    GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;    GoogleStyle.ObjCSpaceAfterProperty = false; @@ -434,7 +567,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {    GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;    if (Language == FormatStyle::LK_Java) { -    GoogleStyle.AlignAfterOpenBracket = false; +    GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;      GoogleStyle.AlignOperands = false;      GoogleStyle.AlignTrailingComments = false;      GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; @@ -445,11 +578,13 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {      GoogleStyle.SpaceAfterCStyleCast = true;      GoogleStyle.SpacesBeforeTrailingComments = 1;    } else if (Language == FormatStyle::LK_JavaScript) { +    GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; +    GoogleStyle.AlignOperands = false; +    GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; +    GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;      GoogleStyle.BreakBeforeTernaryOperators = false;      GoogleStyle.MaxEmptyLinesToKeep = 3;      GoogleStyle.SpacesInContainerLiterals = false; -    GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; -    GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;    } else if (Language == FormatStyle::LK_Proto) {      GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;      GoogleStyle.SpacesInContainerLiterals = false; @@ -462,8 +597,9 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {    FormatStyle ChromiumStyle = getGoogleStyle(Language);    if (Language == FormatStyle::LK_Java) {      ChromiumStyle.AllowShortIfStatementsOnASingleLine = true; -    ChromiumStyle.IndentWidth = 4; +    ChromiumStyle.BreakAfterJavaFieldAnnotations = true;      ChromiumStyle.ContinuationIndentWidth = 8; +    ChromiumStyle.IndentWidth = 4;    } else {      ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;      ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; @@ -472,8 +608,7 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {      ChromiumStyle.BinPackParameters = false;      ChromiumStyle.DerivePointerAlignment = false;    } -  ChromiumStyle.MacroBlockBegin = "^IPC_BEGIN_MESSAGE_MAP$"; -  ChromiumStyle.MacroBlockBegin = "^IPC_END_MESSAGE_MAP$"; +  ChromiumStyle.SortIncludes = false;    return ChromiumStyle;  } @@ -481,6 +616,8 @@ FormatStyle getMozillaStyle() {    FormatStyle MozillaStyle = getLLVMStyle();    MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;    MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; +  MozillaStyle.AlwaysBreakAfterReturnType = +      FormatStyle::RTBS_TopLevelDefinitions;    MozillaStyle.AlwaysBreakAfterDefinitionReturnType =        FormatStyle::DRTBS_TopLevel;    MozillaStyle.AlwaysBreakTemplateDeclarations = true; @@ -500,11 +637,11 @@ FormatStyle getMozillaStyle() {  FormatStyle getWebKitStyle() {    FormatStyle Style = getLLVMStyle();    Style.AccessModifierOffset = -4; -  Style.AlignAfterOpenBracket = false; +  Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;    Style.AlignOperands = false;    Style.AlignTrailingComments = false;    Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; -  Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; +  Style.BreakBeforeBraces = FormatStyle::BS_WebKit;    Style.BreakConstructorInitializersBeforeComma = true;    Style.Cpp11BracedListStyle = false;    Style.ColumnLimit = 0; @@ -520,6 +657,7 @@ FormatStyle getWebKitStyle() {  FormatStyle getGNUStyle() {    FormatStyle Style = getLLVMStyle();    Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All; +  Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;    Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;    Style.BreakBeforeBraces = FormatStyle::BS_GNU;    Style.BreakBeforeTernaryOperators = true; @@ -533,6 +671,7 @@ FormatStyle getGNUStyle() {  FormatStyle getNoStyle() {    FormatStyle NoStyle = getLLVMStyle();    NoStyle.DisableFormat = true; +  NoStyle.SortIncludes = false;    return NoStyle;  } @@ -612,7 +751,7 @@ std::string configurationAsText(const FormatStyle &Style) {    llvm::yaml::Output Output(Stream);    // We use the same mapping method for input and output, so we need a non-const    // reference here. -  FormatStyle NonConstStyle = Style; +  FormatStyle NonConstStyle = expandPresets(Style);    Output << NonConstStyle;    return Stream.str();  } @@ -644,6 +783,8 @@ public:      assert(FirstInLineIndex == 0);      do {        Tokens.push_back(getNextToken()); +      if (Style.Language == FormatStyle::LK_JavaScript) +        tryParseJSRegexLiteral();        tryMergePreviousTokens();        if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline)          FirstInLineIndex = Tokens.size() - 1; @@ -663,10 +804,6 @@ private:        return;      if (Style.Language == FormatStyle::LK_JavaScript) { -      if (tryMergeJSRegexLiteral()) -        return; -      if (tryMergeEscapeSequence()) -        return;        if (tryMergeTemplateString())          return; @@ -738,96 +875,97 @@ private:      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 != "\\") -      return false; -    ++Previous->ColumnWidth; -    StringRef Text = Previous->TokenText; -    Previous->TokenText = StringRef(Text.data(), Text.size() + 1); -    resetLexer(SourceMgr.getFileOffset(Tokens.back()->Tok.getLocation()) + 1); -    Tokens.resize(Tokens.size() - 1); -    Column = Previous->OriginalColumn + Previous->ColumnWidth; -    return true; +  // Returns \c true if \p Tok can only be followed by an operand in JavaScript. +  bool precedesOperand(FormatToken *Tok) { +    // NB: This is not entirely correct, as an r_paren can introduce an operand +    // location in e.g. `if (foo) /bar/.exec(...);`. That is a rare enough +    // corner case to not matter in practice, though. +    return Tok->isOneOf(tok::period, tok::l_paren, tok::comma, tok::l_brace, +                        tok::r_brace, tok::l_square, tok::semi, tok::exclaim, +                        tok::colon, tok::question, tok::tilde) || +           Tok->isOneOf(tok::kw_return, tok::kw_do, tok::kw_case, tok::kw_throw, +                        tok::kw_else, tok::kw_new, tok::kw_delete, tok::kw_void, +                        tok::kw_typeof, Keywords.kw_instanceof, +                        Keywords.kw_in) || +           Tok->isBinaryOperator();    } -  // 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) -      return false; +  bool canPrecedeRegexLiteral(FormatToken *Prev) { +    if (!Prev) +      return true; -    // If this is a string literal with a slash inside, compute the slash's -    // offset and try to find the beginning of the regex literal. -    // Also look at tok::unknown, as it can be an unterminated char literal. -    size_t SlashInStringPos = StringRef::npos; -    if (Tokens.back()->isOneOf(tok::string_literal, tok::char_constant, -                               tok::unknown)) { -      // Start search from position 1 as otherwise, this is an unknown token -      // for an unterminated /*-comment which is handled elsewhere. -      SlashInStringPos = Tokens.back()->TokenText.find('/', 1); -      if (SlashInStringPos == StringRef::npos) -        return false; -    } +    // Regex literals can only follow after prefix unary operators, not after +    // postfix unary operators. If the '++' is followed by a non-operand +    // introducing token, the slash here is the operand and not the start of a +    // regex. +    if (Prev->isOneOf(tok::plusplus, tok::minusminus)) +      return (Tokens.size() < 3 || precedesOperand(Tokens[Tokens.size() - 3])); -    // If a regex literal ends in "\//", this gets represented by an unknown -    // token "\" and a comment. -    bool MightEndWithEscapedSlash = -        Tokens.back()->is(tok::comment) && -        Tokens.back()->TokenText.startswith("//") && -        Tokens[Tokens.size() - 2]->TokenText == "\\"; -    if (!MightEndWithEscapedSlash && SlashInStringPos == StringRef::npos && -        (Tokens.back()->isNot(tok::slash) || -         (Tokens[Tokens.size() - 2]->is(tok::unknown) && -          Tokens[Tokens.size() - 2]->TokenText == "\\"))) +    // The previous token must introduce an operand location where regex +    // literals can occur. +    if (!precedesOperand(Prev))        return false; -    unsigned TokenCount = 0; +    return true; +  } + +  // Tries to parse a JavaScript Regex literal starting at the current token, +  // if that begins with a slash and is in a location where JavaScript allows +  // regex literals. Changes the current token to a regex literal and updates +  // its text if successful. +  void tryParseJSRegexLiteral() { +    FormatToken *RegexToken = Tokens.back(); +    if (!RegexToken->isOneOf(tok::slash, tok::slashequal)) +      return; + +    FormatToken *Prev = nullptr;      for (auto I = Tokens.rbegin() + 1, E = Tokens.rend(); I != E; ++I) { -      ++TokenCount; -      auto Prev = I + 1; -      while (Prev != E && Prev[0]->is(tok::comment)) -        ++Prev; -      if (I[0]->isOneOf(tok::slash, tok::slashequal) && -          (Prev == E || -           ((Prev[0]->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) || -             Prev[0]->isBinaryOperator())))) { -        unsigned LastColumn = Tokens.back()->OriginalColumn; -        SourceLocation Loc = Tokens.back()->Tok.getLocation(); -        if (MightEndWithEscapedSlash) { -          // This regex literal ends in '\//'. Skip past the '//' of the last -          // token and re-start lexing from there. -          resetLexer(SourceMgr.getFileOffset(Loc) + 2); -        } else if (SlashInStringPos != StringRef::npos) { -          // This regex literal ends in a string_literal with a slash inside. -          // Calculate end column and reset lexer appropriately. -          resetLexer(SourceMgr.getFileOffset(Loc) + SlashInStringPos + 1); -          LastColumn += SlashInStringPos; -        } -        Tokens.resize(Tokens.size() - TokenCount); -        Tokens.back()->Tok.setKind(tok::unknown); -        Tokens.back()->Type = TT_RegexLiteral; -        // Treat regex literals like other string_literals. -        Tokens.back()->Tok.setKind(tok::string_literal); -        Tokens.back()->ColumnWidth += LastColumn - I[0]->OriginalColumn; -        return true; +      // NB: Because previous pointers are not initialized yet, this cannot use +      // Token.getPreviousNonComment. +      if ((*I)->isNot(tok::comment)) { +        Prev = *I; +        break;        } +    } -      // There can't be a newline inside a regex literal. -      if (I[0]->NewlinesBefore > 0) -        return false; +    if (!canPrecedeRegexLiteral(Prev)) +      return; + +    // 'Manually' lex ahead in the current file buffer. +    const char *Offset = Lex->getBufferLocation(); +    const char *RegexBegin = Offset - RegexToken->TokenText.size(); +    StringRef Buffer = Lex->getBuffer(); +    bool InCharacterClass = false; +    bool HaveClosingSlash = false; +    for (; !HaveClosingSlash && Offset != Buffer.end(); ++Offset) { +      // Regular expressions are terminated with a '/', which can only be +      // escaped using '\' or a character class between '[' and ']'. +      // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5. +      switch (*Offset) { +      case '\\': +        // Skip the escaped character. +        ++Offset; +        break; +      case '[': +        InCharacterClass = true; +        break; +      case ']': +        InCharacterClass = false; +        break; +      case '/': +        if (!InCharacterClass) +          HaveClosingSlash = true; +        break; +      }      } -    return false; + +    RegexToken->Type = TT_RegexLiteral; +    // Treat regex literals like other string_literals. +    RegexToken->Tok.setKind(tok::string_literal); +    RegexToken->TokenText = StringRef(RegexBegin, Offset - RegexBegin); +    RegexToken->ColumnWidth = RegexToken->TokenText.size(); + +    resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));    }    bool tryMergeTemplateString() { @@ -1138,7 +1276,13 @@ private:        FormatTok->Tok.setIdentifierInfo(&Info);        FormatTok->Tok.setKind(Info.getTokenID());        if (Style.Language == FormatStyle::LK_Java && -          FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete)) { +          FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete, +                             tok::kw_operator)) { +        FormatTok->Tok.setKind(tok::identifier); +        FormatTok->Tok.setIdentifierInfo(nullptr); +      } else if (Style.Language == FormatStyle::LK_JavaScript && +                 FormatTok->isOneOf(tok::kw_struct, tok::kw_union, +                                    tok::kw_operator)) {          FormatTok->Tok.setKind(tok::identifier);          FormatTok->Tok.setIdentifierInfo(nullptr);        } @@ -1485,11 +1629,46 @@ private:      return Text.count('\r') * 2 > Text.count('\n');    } +  bool +  hasCpp03IncompatibleFormat(const SmallVectorImpl<AnnotatedLine *> &Lines) { +    for (const AnnotatedLine* Line : Lines) { +      if (hasCpp03IncompatibleFormat(Line->Children)) +        return true; +      for (FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next) { +        if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) { +          if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener)) +            return true; +          if (Tok->is(TT_TemplateCloser) && +              Tok->Previous->is(TT_TemplateCloser)) +            return true; +        } +      } +    } +    return false; +  } + +  int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) { +    int AlignmentDiff = 0; +    for (const AnnotatedLine* Line : Lines) { +      AlignmentDiff += countVariableAlignments(Line->Children); +      for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { +        if (!Tok->is(TT_PointerOrReference)) +          continue; +        bool SpaceBefore = +            Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd(); +        bool SpaceAfter = Tok->Next->WhitespaceRange.getBegin() != +                          Tok->Next->WhitespaceRange.getEnd(); +        if (SpaceBefore && !SpaceAfter) +          ++AlignmentDiff; +        if (!SpaceBefore && SpaceAfter) +          --AlignmentDiff; +      } +    } +    return AlignmentDiff; +  } +    void    deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { -    unsigned CountBoundToVariable = 0; -    unsigned CountBoundToType = 0; -    bool HasCpp03IncompatibleFormat = false;      bool HasBinPackedFunction = false;      bool HasOnePerLineFunction = false;      for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { @@ -1497,25 +1676,6 @@ private:          continue;        FormatToken *Tok = AnnotatedLines[i]->First->Next;        while (Tok->Next) { -        if (Tok->is(TT_PointerOrReference)) { -          bool SpacesBefore = -              Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd(); -          bool SpacesAfter = Tok->Next->WhitespaceRange.getBegin() != -                             Tok->Next->WhitespaceRange.getEnd(); -          if (SpacesBefore && !SpacesAfter) -            ++CountBoundToVariable; -          else if (!SpacesBefore && SpacesAfter) -            ++CountBoundToType; -        } - -        if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) { -          if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener)) -            HasCpp03IncompatibleFormat = true; -          if (Tok->is(TT_TemplateCloser) && -              Tok->Previous->is(TT_TemplateCloser)) -            HasCpp03IncompatibleFormat = true; -        } -          if (Tok->PackingKind == PPK_BinPacked)            HasBinPackedFunction = true;          if (Tok->PackingKind == PPK_OnePerLine) @@ -1524,16 +1684,14 @@ private:          Tok = Tok->Next;        }      } -    if (Style.DerivePointerAlignment) { -      if (CountBoundToType > CountBoundToVariable) -        Style.PointerAlignment = FormatStyle::PAS_Left; -      else if (CountBoundToType < CountBoundToVariable) -        Style.PointerAlignment = FormatStyle::PAS_Right; -    } -    if (Style.Standard == FormatStyle::LS_Auto) { -      Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11 -                                                  : FormatStyle::LS_Cpp03; -    } +    if (Style.DerivePointerAlignment) +      Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0 +                                   ? FormatStyle::PAS_Left +                                   : FormatStyle::PAS_Right; +    if (Style.Standard == FormatStyle::LS_Auto) +      Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines) +                           ? FormatStyle::LS_Cpp11 +                           : FormatStyle::LS_Cpp03;      BinPackInconclusiveFunctions =          HasBinPackedFunction || !HasOnePerLineFunction;    } @@ -1558,15 +1716,175 @@ private:    bool BinPackInconclusiveFunctions;  }; +struct IncludeDirective { +  StringRef Filename; +  StringRef Text; +  unsigned Offset; +  int Category; +}; +  } // end anonymous namespace +// Determines whether 'Ranges' intersects with ('Start', 'End'). +static bool affectsRange(ArrayRef<tooling::Range> Ranges, unsigned Start, +                         unsigned End) { +  for (auto Range : Ranges) { +    if (Range.getOffset() < End && +        Range.getOffset() + Range.getLength() > Start) +      return true; +  } +  return false; +} + +// Sorts a block of includes given by 'Includes' alphabetically adding the +// necessary replacement to 'Replaces'. 'Includes' must be in strict source +// order. +static void sortIncludes(const FormatStyle &Style, +                         const SmallVectorImpl<IncludeDirective> &Includes, +                         ArrayRef<tooling::Range> Ranges, StringRef FileName, +                         tooling::Replacements &Replaces, unsigned *Cursor) { +  if (!affectsRange(Ranges, Includes.front().Offset, +                    Includes.back().Offset + Includes.back().Text.size())) +    return; +  SmallVector<unsigned, 16> Indices; +  for (unsigned i = 0, e = Includes.size(); i != e; ++i) +    Indices.push_back(i); +  std::sort(Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) { +    return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) < +           std::tie(Includes[RHSI].Category, Includes[RHSI].Filename); +  }); + +  // If the #includes are out of order, we generate a single replacement fixing +  // the entire block. Otherwise, no replacement is generated. +  bool OutOfOrder = false; +  for (unsigned i = 1, e = Indices.size(); i != e; ++i) { +    if (Indices[i] != i) { +      OutOfOrder = true; +      break; +    } +  } +  if (!OutOfOrder) +    return; + +  std::string result; +  bool CursorMoved = false; +  for (unsigned Index : Indices) { +    if (!result.empty()) +      result += "\n"; +    result += Includes[Index].Text; + +    if (Cursor && !CursorMoved) { +      unsigned Start = Includes[Index].Offset; +      unsigned End = Start + Includes[Index].Text.size(); +      if (*Cursor >= Start && *Cursor < End) { +        *Cursor = Includes.front().Offset + result.size() + *Cursor - End; +        CursorMoved = true; +      } +    } +  } + +  // Sorting #includes shouldn't change their total number of characters. +  // This would otherwise mess up 'Ranges'. +  assert(result.size() == +         Includes.back().Offset + Includes.back().Text.size() - +             Includes.front().Offset); + +  Replaces.insert(tooling::Replacement(FileName, Includes.front().Offset, +                                       result.size(), result)); +} + +tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, +                                   ArrayRef<tooling::Range> Ranges, +                                   StringRef FileName, unsigned *Cursor) { +  tooling::Replacements Replaces; +  if (!Style.SortIncludes) +    return Replaces; + +  unsigned Prev = 0; +  unsigned SearchFrom = 0; +  llvm::Regex IncludeRegex( +      R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))"); +  SmallVector<StringRef, 4> Matches; +  SmallVector<IncludeDirective, 16> IncludesInBlock; + +  // In compiled files, consider the first #include to be the main #include of +  // the file if it is not a system #include. This ensures that the header +  // doesn't have hidden dependencies +  // (http://llvm.org/docs/CodingStandards.html#include-style). +  // +  // FIXME: Do some sanity checking, e.g. edit distance of the base name, to fix +  // cases where the first #include is unlikely to be the main header. +  bool IsSource = FileName.endswith(".c") || FileName.endswith(".cc") || +                  FileName.endswith(".cpp") || FileName.endswith(".c++") || +                  FileName.endswith(".cxx") || FileName.endswith(".m") || +                  FileName.endswith(".mm"); +  StringRef FileStem = llvm::sys::path::stem(FileName); +  bool FirstIncludeBlock = true; +  bool MainIncludeFound = false; + +  // Create pre-compiled regular expressions for the #include categories. +  SmallVector<llvm::Regex, 4> CategoryRegexs; +  for (const auto &Category : Style.IncludeCategories) +    CategoryRegexs.emplace_back(Category.Regex); + +  bool FormattingOff = false; + +  for (;;) { +    auto Pos = Code.find('\n', SearchFrom); +    StringRef Line = +        Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev); + +    StringRef Trimmed = Line.trim(); +    if (Trimmed == "// clang-format off") +      FormattingOff = true; +    else if (Trimmed == "// clang-format on") +      FormattingOff = false; + +    if (!FormattingOff && !Line.endswith("\\")) { +      if (IncludeRegex.match(Line, &Matches)) { +        StringRef IncludeName = Matches[2]; +        int Category = INT_MAX; +        for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i) { +          if (CategoryRegexs[i].match(IncludeName)) { +            Category = Style.IncludeCategories[i].Priority; +            break; +          } +        } +        if (IsSource && !MainIncludeFound && Category > 0 && +            FirstIncludeBlock && IncludeName.startswith("\"")) { +          StringRef HeaderStem = +              llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1)); +          if (FileStem.startswith(HeaderStem)) { +            Category = 0; +            MainIncludeFound = true; +          } +        } +        IncludesInBlock.push_back({IncludeName, Line, Prev, Category}); +      } else if (!IncludesInBlock.empty()) { +        sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, +                     Cursor); +        IncludesInBlock.clear(); +        FirstIncludeBlock = false; +      } +      Prev = Pos + 1; +    } +    if (Pos == StringRef::npos || Pos + 1 == Code.size()) +      break; +    SearchFrom = Pos + 1; +  } +  if (!IncludesInBlock.empty()) +    sortIncludes(Style, IncludesInBlock, Ranges, FileName, Replaces, Cursor); +  return Replaces; +} +  tooling::Replacements reformat(const FormatStyle &Style,                                 SourceManager &SourceMgr, FileID ID,                                 ArrayRef<CharSourceRange> Ranges,                                 bool *IncompleteFormat) { -  if (Style.DisableFormat) +  FormatStyle Expanded = expandPresets(Style); +  if (Expanded.DisableFormat)      return tooling::Replacements(); -  Formatter formatter(Style, SourceMgr, ID, Ranges); +  Formatter formatter(Expanded, SourceMgr, ID, Ranges);    return formatter.format(IncompleteFormat);  } @@ -1576,18 +1894,17 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,    if (Style.DisableFormat)      return tooling::Replacements(); -  FileManager Files((FileSystemOptions())); +  IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( +      new vfs::InMemoryFileSystem); +  FileManager Files(FileSystemOptions(), InMemoryFileSystem);    DiagnosticsEngine Diagnostics(        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),        new DiagnosticOptions);    SourceManager SourceMgr(Diagnostics, Files); -  std::unique_ptr<llvm::MemoryBuffer> Buf = -      llvm::MemoryBuffer::getMemBuffer(Code, FileName); -  const clang::FileEntry *Entry = -      Files.getVirtualFile(FileName, Buf->getBufferSize(), 0); -  SourceMgr.overrideFileContents(Entry, std::move(Buf)); -  FileID ID = -      SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User); +  InMemoryFileSystem->addFile(FileName, 0, +                              llvm::MemoryBuffer::getMemBuffer(Code, FileName)); +  FileID ID = SourceMgr.createFileID(Files.getFile(FileName), SourceLocation(), +                                     clang::SrcMgr::C_User);    SourceLocation StartOfFile = SourceMgr.getLocForStartOfFile(ID);    std::vector<CharSourceRange> CharRanges;    for (const tooling::Range &Range : Ranges) { @@ -1610,6 +1927,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {    LangOpts.ObjC1 = 1;    LangOpts.ObjC2 = 1;    LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally. +  LangOpts.DeclSpecKeyword = 1; // To get __declspec.    return LangOpts;  } @@ -1625,15 +1943,15 @@ const char *StyleOptionHelpDescription =      "  -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";  static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { -  if (FileName.endswith(".java")) { +  if (FileName.endswith(".java"))      return FormatStyle::LK_Java; -  } else if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts")) { -    // JavaScript or TypeScript. -    return FormatStyle::LK_JavaScript; -  } else if (FileName.endswith_lower(".proto") || -             FileName.endswith_lower(".protodevel")) { +  if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts")) +    return FormatStyle::LK_JavaScript; // JavaScript or TypeScript. +  if (FileName.endswith_lower(".proto") || +      FileName.endswith_lower(".protodevel"))      return FormatStyle::LK_Proto; -  } +  if (FileName.endswith_lower(".td")) +    return FormatStyle::LK_TableGen;    return FormatStyle::LK_Cpp;  }  | 
