summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Format/Format.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Format/Format.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Format/Format.cpp616
1 files changed, 467 insertions, 149 deletions
diff --git a/contrib/llvm/tools/clang/lib/Format/Format.cpp b/contrib/llvm/tools/clang/lib/Format/Format.cpp
index 382ae81..5068fca 100644
--- a/contrib/llvm/tools/clang/lib/Format/Format.cpp
+++ b/contrib/llvm/tools/clang/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;
}
OpenPOWER on IntegriCloud