sstwcw updated this revision to Diff 416025.
sstwcw added a comment.
Use the name spaceRequiredBetween.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D121755/new/
https://reviews.llvm.org/D121755
Files:
clang/lib/Format/TokenAnnotator.cpp
clang/lib/Format/TokenAnnotator.h
Index: clang/lib/Format/TokenAnnotator.h
===================================================================
--- clang/lib/Format/TokenAnnotator.h
+++ clang/lib/Format/TokenAnnotator.h
@@ -172,8 +172,6 @@
bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
const FormatToken &Right);
- bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right);
-
bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2733,7 +2733,7 @@
}
}
} else if (Current->SpacesRequiredBefore == 0 &&
- spaceRequiredBefore(Line, *Current)) {
+ spaceRequiredBetween(Line, *Prev, *Current)) {
Current->SpacesRequiredBefore = 1;
}
@@ -3071,6 +3071,406 @@
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Left,
const FormatToken &Right) {
+ // If the token is finalized don't touch it (as it could be in a
+ // clang-format-off section).
+ if (Left.Finalized)
+ return Right.hasWhitespaceBefore();
+
+ if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
+ return true; // Never ever merge two identifiers.
+
+ // Leave a space between * and /* to avoid C4138 `comment end` found outside
+ // of comment.
+ if (Left.is(tok::star) && Right.is(tok::comment))
+ return true;
+
+ if (Style.isCpp()) {
+ // Space between import <iostream>.
+ // or import .....;
+ if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis))
+ return true;
+ // Space between `module :` and `import :`.
+ if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) &&
+ Right.is(TT_ModulePartitionColon))
+ return true;
+ // No space between import foo:bar but keep a space between import :bar;
+ if (Left.is(tok::identifier) && Right.is(TT_ModulePartitionColon))
+ return false;
+ // No space between :bar;
+ if (Left.is(TT_ModulePartitionColon) &&
+ Right.isOneOf(tok::identifier, tok::kw_private))
+ return false;
+ if (Left.is(tok::ellipsis) && Right.is(tok::identifier) &&
+ Line.First->is(Keywords.kw_import))
+ return false;
+ // Space in __attribute__((attr)) ::type.
+ if (Left.is(TT_AttributeParen) && Right.is(tok::coloncolon))
+ return true;
+
+ if (Left.is(tok::kw_operator))
+ return Right.is(tok::coloncolon);
+ if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) &&
+ !Left.opensScope() && Style.SpaceBeforeCpp11BracedList)
+ return true;
+ if (Left.is(tok::less) && Left.is(TT_OverloadedOperator) &&
+ Right.is(TT_TemplateOpener))
+ return true;
+ } else if (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) {
+ if (Right.is(tok::period) &&
+ Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
+ Keywords.kw_repeated, Keywords.kw_extend))
+ return true;
+ if (Right.is(tok::l_paren) &&
+ Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
+ return true;
+ if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName))
+ return true;
+ // Slashes occur in text protocol extension syntax: [type/type] { ... }.
+ if (Left.is(tok::slash) || Right.is(tok::slash))
+ return false;
+ if (Left.MatchingParen &&
+ Left.MatchingParen->is(TT_ProtoExtensionLSquare) &&
+ Right.isOneOf(tok::l_brace, tok::less))
+ return !Style.Cpp11BracedListStyle;
+ // A percent is probably part of a formatting specification, such as %lld.
+ if (Left.is(tok::percent))
+ return false;
+ // Preserve the existence of a space before a percent for cases like 0x%04x
+ // and "%d %d"
+ if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
+ return Right.hasWhitespaceBefore();
+ } else if (Style.isJson()) {
+ if (Right.is(tok::colon))
+ return false;
+ } else if (Style.isCSharp()) {
+ // Require spaces around '{' and before '}' unless they appear in
+ // interpolated strings. Interpolated strings are merged into a single token
+ // so cannot have spaces inserted by this function.
+
+ // No space between 'this' and '['
+ if (Left.is(tok::kw_this) && Right.is(tok::l_square))
+ return false;
+
+ // No space between 'new' and '('
+ if (Left.is(tok::kw_new) && Right.is(tok::l_paren))
+ return false;
+
+ // Space before { (including space within '{ {').
+ if (Right.is(tok::l_brace))
+ return true;
+
+ // Spaces inside braces.
+ if (Left.is(tok::l_brace) && Right.isNot(tok::r_brace))
+ return true;
+
+ if (Left.isNot(tok::l_brace) && Right.is(tok::r_brace))
+ return true;
+
+ // Spaces around '=>'.
+ if (Left.is(TT_FatArrow) || Right.is(TT_FatArrow))
+ return true;
+
+ // No spaces around attribute target colons
+ if (Left.is(TT_AttributeColon) || Right.is(TT_AttributeColon))
+ return false;
+
+ // space between type and variable e.g. Dictionary<string,string> foo;
+ if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
+ return true;
+
+ // spaces inside square brackets.
+ if (Left.is(tok::l_square) || Right.is(tok::r_square))
+ return Style.SpacesInSquareBrackets;
+
+ // No space before ? in nullable types.
+ if (Right.is(TT_CSharpNullable))
+ return false;
+
+ // No space before null forgiving '!'.
+ if (Right.is(TT_NonNullAssertion))
+ return false;
+
+ // No space between consecutive commas '[,,]'.
+ if (Left.is(tok::comma) && Right.is(tok::comma))
+ return false;
+
+ // space after var in `var (key, value)`
+ if (Left.is(Keywords.kw_var) && Right.is(tok::l_paren))
+ return true;
+
+ // space between keywords and paren e.g. "using ("
+ if (Right.is(tok::l_paren))
+ if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when,
+ Keywords.kw_lock))
+ return Style.SpaceBeforeParensOptions.AfterControlStatements ||
+ spaceRequiredBeforeParens(Right);
+
+ // space between method modifier and opening parenthesis of a tuple return
+ // type
+ if (Left.isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
+ tok::kw_virtual, tok::kw_extern, tok::kw_static,
+ Keywords.kw_internal, Keywords.kw_abstract,
+ Keywords.kw_sealed, Keywords.kw_override,
+ Keywords.kw_async, Keywords.kw_unsafe) &&
+ Right.is(tok::l_paren))
+ return true;
+ } else if (Style.isJavaScript()) {
+ if (Left.is(TT_FatArrow))
+ return true;
+ // for await ( ...
+ if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous &&
+ Left.Previous->is(tok::kw_for))
+ return true;
+ if (Left.is(Keywords.kw_async) && Right.is(tok::l_paren) &&
+ Right.MatchingParen) {
+ const FormatToken *Next = Right.MatchingParen->getNextNonComment();
+ // An async arrow function, for example: `x = async () => foo();`,
+ // as opposed to calling a function called async: `x = async();`
+ if (Next && Next->is(TT_FatArrow))
+ return true;
+ }
+ if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
+ (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
+ return false;
+ // In tagged template literals ("html`bar baz`"), there is no space between
+ // the tag identifier and the template string.
+ if (Keywords.IsJavaScriptIdentifier(Left,
+ /* AcceptIdentifierName= */ false) &&
+ Right.is(TT_TemplateString))
+ return false;
+ if (Right.is(tok::star) &&
+ Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+ return false;
+ if (Right.isOneOf(tok::l_brace, tok::l_square) &&
+ Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
+ return true;
+ if (Right.is(tok::l_paren)) {
+ // JS methods can use some keywords as names (e.g. `delete()`).
+ if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo())
+ return false;
+ // Valid JS method names can include keywords, e.g. `foo.delete()` or
+ // `bar.instanceof()`. Recognize call positions by preceding period.
+ if (Left.Previous && Left.Previous->is(tok::period) &&
+ Left.Tok.getIdentifierInfo())
+ return false;
+ // Additional unary JavaScript operators that need a space after.
+ if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof,
+ tok::kw_void))
+ return true;
+ }
+ // `foo as const;` casts into a const type.
+ if (Left.endsSequence(tok::kw_const, Keywords.kw_as))
+ return false;
+ if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
+ tok::kw_const) ||
+ // "of" is only a keyword if it appears after another identifier
+ // (e.g. as "const x of y" in a for loop), or after a destructuring
+ // operation (const [x, y] of z, const {a, b} of c).
+ (Left.is(Keywords.kw_of) && Left.Previous &&
+ (Left.Previous->is(tok::identifier) ||
+ Left.Previous->isOneOf(tok::r_square, tok::r_brace)))) &&
+ (!Left.Previous || !Left.Previous->is(tok::period)))
+ return true;
+ if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous &&
+ Left.Previous->is(tok::period) && Right.is(tok::l_paren))
+ return false;
+ if (Left.is(Keywords.kw_as) &&
+ Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren))
+ return true;
+ if (Left.is(tok::kw_default) && Left.Previous &&
+ Left.Previous->is(tok::kw_export))
+ return true;
+ if (Left.is(Keywords.kw_is) && Right.is(tok::l_brace))
+ return true;
+ if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion))
+ return false;
+ if (Left.is(TT_JsTypeOperator) || Right.is(TT_JsTypeOperator))
+ return false;
+ if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
+ Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
+ return false;
+ if (Left.is(tok::ellipsis))
+ return false;
+ if (Left.is(TT_TemplateCloser) &&
+ !Right.isOneOf(tok::equal, tok::l_brace, tok::comma, tok::l_square,
+ Keywords.kw_implements, Keywords.kw_extends))
+ // Type assertions ('<type>expr') are not followed by whitespace. Other
+ // locations that should have whitespace following are identified by the
+ // above set of follower tokens.
+ return false;
+ if (Right.is(TT_NonNullAssertion))
+ return false;
+ if (Left.is(TT_NonNullAssertion) &&
+ Right.isOneOf(Keywords.kw_as, Keywords.kw_in))
+ return true; // "x! as string", "x! in y"
+ } else if (Style.Language == FormatStyle::LK_Java) {
+ if (Left.is(tok::r_square) && Right.is(tok::l_brace))
+ return true;
+ if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren))
+ return Style.SpaceBeforeParensOptions.AfterControlStatements ||
+ spaceRequiredBeforeParens(Right);
+ if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private,
+ tok::kw_protected) ||
+ Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract,
+ Keywords.kw_native)) &&
+ Right.is(TT_TemplateOpener))
+ return true;
+ }
+ if (Left.is(TT_ImplicitStringLiteral))
+ return Right.hasWhitespaceBefore();
+ if (Line.Type == LT_ObjCMethodDecl) {
+ if (Left.is(TT_ObjCMethodSpecifier))
+ return true;
+ if (Left.is(tok::r_paren) && canBeObjCSelectorComponent(Right))
+ // Don't space between ')' and <id> or ')' and 'new'. 'new' is not a
+ // keyword in Objective-C, and '+ (instancetype)new;' is a standard class
+ // method declaration.
+ return false;
+ }
+ if (Line.Type == LT_ObjCProperty &&
+ (Right.is(tok::equal) || Left.is(tok::equal)))
+ return false;
+
+ if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
+ Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow))
+ return true;
+ if (Left.is(tok::comma) && !Right.is(TT_OverloadedOperatorLParen))
+ return true;
+ if (Right.is(tok::comma))
+ return false;
+ if (Right.is(TT_ObjCBlockLParen))
+ return true;
+ if (Right.is(TT_CtorInitializerColon))
+ return Style.SpaceBeforeCtorInitializerColon;
+ if (Right.is(TT_InheritanceColon) && !Style.SpaceBeforeInheritanceColon)
+ return false;
+ if (Right.is(TT_RangeBasedForLoopColon) &&
+ !Style.SpaceBeforeRangeBasedForLoopColon)
+ return false;
+ if (Left.is(TT_BitFieldColon))
+ return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both ||
+ Style.BitFieldColonSpacing == FormatStyle::BFCS_After;
+ if (Right.is(tok::colon)) {
+ if (Line.First->isOneOf(tok::kw_default, tok::kw_case))
+ return Style.SpaceBeforeCaseColon;
+ const FormatToken *Next = Right.getNextNonComment();
+ if (!Next || Next->is(tok::semi))
+ return false;
+ if (Right.is(TT_ObjCMethodExpr))
+ return false;
+ if (Left.is(tok::question))
+ return false;
+ if (Right.is(TT_InlineASMColon) && Left.is(tok::coloncolon))
+ return false;
+ if (Right.is(TT_DictLiteral))
+ return Style.SpacesInContainerLiterals;
+ if (Right.is(TT_AttributeColon))
+ return false;
+ if (Right.is(TT_CSharpNamedArgumentColon))
+ return false;
+ if (Right.is(TT_BitFieldColon))
+ return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both ||
+ Style.BitFieldColonSpacing == FormatStyle::BFCS_Before;
+ return true;
+ }
+ // Do not merge "- -" into "--".
+ if ((Left.isOneOf(tok::minus, tok::minusminus) &&
+ Right.isOneOf(tok::minus, tok::minusminus)) ||
+ (Left.isOneOf(tok::plus, tok::plusplus) &&
+ Right.isOneOf(tok::plus, tok::plusplus)))
+ return true;
+ if (Left.is(TT_UnaryOperator)) {
+ if (!Right.is(tok::l_paren)) {
+ // The alternative operators for ~ and ! are "compl" and "not".
+ // If they are used instead, we do not want to combine them with
+ // the token to the right, unless that is a left paren.
+ if (Left.is(tok::exclaim) && Left.TokenText == "not")
+ return true;
+ if (Left.is(tok::tilde) && Left.TokenText == "compl")
+ return true;
+ // Lambda captures allow for a lone &, so "&]" needs to be properly
+ // handled.
+ if (Left.is(tok::amp) && Right.is(tok::r_square))
+ return Style.SpacesInSquareBrackets;
+ }
+ return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) ||
+ Right.is(TT_BinaryOperator);
+ }
+
+ // If the next token is a binary operator or a selector name, we have
+ // incorrectly classified the parenthesis as a cast. FIXME: Detect correctly.
+ if (Left.is(TT_CastRParen))
+ return Style.SpaceAfterCStyleCast ||
+ Right.isOneOf(TT_BinaryOperator, TT_SelectorName);
+
+ auto ShouldAddSpacesInAngles = [this, &Right]() {
+ if (this->Style.SpacesInAngles == FormatStyle::SIAS_Always)
+ return true;
+ if (this->Style.SpacesInAngles == FormatStyle::SIAS_Leave)
+ return Right.hasWhitespaceBefore();
+ return false;
+ };
+
+ if (Left.is(tok::greater) && Right.is(tok::greater)) {
+ if (Style.Language == FormatStyle::LK_TextProto ||
+ (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral)))
+ return !Style.Cpp11BracedListStyle;
+ return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
+ ((Style.Standard < FormatStyle::LS_Cpp11) ||
+ ShouldAddSpacesInAngles());
+ }
+ if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
+ Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
+ (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod)))
+ return false;
+ if (!Style.SpaceBeforeAssignmentOperators && Left.isNot(TT_TemplateCloser) &&
+ Right.getPrecedence() == prec::Assignment)
+ return false;
+ if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) &&
+ (Left.is(tok::identifier) || Left.is(tok::kw_this)))
+ return false;
+ if (Right.is(tok::coloncolon) && Left.is(tok::identifier))
+ // Generally don't remove existing spaces between an identifier and "::".
+ // The identifier might actually be a macro name such as ALWAYS_INLINE. If
+ // this turns out to be too lenient, add analysis of the identifier itself.
+ return Right.hasWhitespaceBefore();
+ if (Right.is(tok::coloncolon) &&
+ !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren))
+ // Put a space between < and :: in vector< ::std::string >
+ return (Left.is(TT_TemplateOpener) &&
+ ((Style.Standard < FormatStyle::LS_Cpp11) ||
+ ShouldAddSpacesInAngles())) ||
+ !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
+ tok::kw___super, TT_TemplateOpener,
+ TT_TemplateCloser)) ||
+ (Left.is(tok::l_paren) && Style.SpacesInParentheses);
+ if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
+ return ShouldAddSpacesInAngles();
+ // Space before TT_StructuredBindingLSquare.
+ if (Right.is(TT_StructuredBindingLSquare))
+ return !Left.isOneOf(tok::amp, tok::ampamp) ||
+ getTokenReferenceAlignment(Left) != FormatStyle::PAS_Right;
+ // Space before & or && following a TT_StructuredBindingLSquare.
+ if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) &&
+ Right.isOneOf(tok::amp, tok::ampamp))
+ return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left;
+ if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
+ (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
+ !Right.is(tok::r_paren)))
+ return true;
+ if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) &&
+ Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen))
+ return false;
+ if (Right.is(tok::less) && Left.isNot(tok::l_paren) &&
+ Line.startsWith(tok::hash))
+ return true;
+ if (Right.is(TT_TrailingUnaryOperator))
+ return false;
+ if (Left.is(TT_RegexLiteral))
+ return false;
+
if (Left.is(tok::kw_return) &&
!Right.isOneOf(tok::semi, tok::r_paren, tok::hashhash))
return true;
@@ -3448,412 +3848,6 @@
return true;
}
-bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
- const FormatToken &Right) {
- const FormatToken &Left = *Right.Previous;
-
- // If the token is finalized don't touch it (as it could be in a
- // clang-format-off section).
- if (Left.Finalized)
- return Right.hasWhitespaceBefore();
-
- if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
- return true; // Never ever merge two identifiers.
-
- // Leave a space between * and /* to avoid C4138 `comment end` found outside
- // of comment.
- if (Left.is(tok::star) && Right.is(tok::comment))
- return true;
-
- if (Style.isCpp()) {
- // Space between import <iostream>.
- // or import .....;
- if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis))
- return true;
- // Space between `module :` and `import :`.
- if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) &&
- Right.is(TT_ModulePartitionColon))
- return true;
- // No space between import foo:bar but keep a space between import :bar;
- if (Left.is(tok::identifier) && Right.is(TT_ModulePartitionColon))
- return false;
- // No space between :bar;
- if (Left.is(TT_ModulePartitionColon) &&
- Right.isOneOf(tok::identifier, tok::kw_private))
- return false;
- if (Left.is(tok::ellipsis) && Right.is(tok::identifier) &&
- Line.First->is(Keywords.kw_import))
- return false;
- // Space in __attribute__((attr)) ::type.
- if (Left.is(TT_AttributeParen) && Right.is(tok::coloncolon))
- return true;
-
- if (Left.is(tok::kw_operator))
- return Right.is(tok::coloncolon);
- if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) &&
- !Left.opensScope() && Style.SpaceBeforeCpp11BracedList)
- return true;
- if (Left.is(tok::less) && Left.is(TT_OverloadedOperator) &&
- Right.is(TT_TemplateOpener))
- return true;
- } else if (Style.Language == FormatStyle::LK_Proto ||
- Style.Language == FormatStyle::LK_TextProto) {
- if (Right.is(tok::period) &&
- Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
- Keywords.kw_repeated, Keywords.kw_extend))
- return true;
- if (Right.is(tok::l_paren) &&
- Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
- return true;
- if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName))
- return true;
- // Slashes occur in text protocol extension syntax: [type/type] { ... }.
- if (Left.is(tok::slash) || Right.is(tok::slash))
- return false;
- if (Left.MatchingParen &&
- Left.MatchingParen->is(TT_ProtoExtensionLSquare) &&
- Right.isOneOf(tok::l_brace, tok::less))
- return !Style.Cpp11BracedListStyle;
- // A percent is probably part of a formatting specification, such as %lld.
- if (Left.is(tok::percent))
- return false;
- // Preserve the existence of a space before a percent for cases like 0x%04x
- // and "%d %d"
- if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
- return Right.hasWhitespaceBefore();
- } else if (Style.isJson()) {
- if (Right.is(tok::colon))
- return false;
- } else if (Style.isCSharp()) {
- // Require spaces around '{' and before '}' unless they appear in
- // interpolated strings. Interpolated strings are merged into a single token
- // so cannot have spaces inserted by this function.
-
- // No space between 'this' and '['
- if (Left.is(tok::kw_this) && Right.is(tok::l_square))
- return false;
-
- // No space between 'new' and '('
- if (Left.is(tok::kw_new) && Right.is(tok::l_paren))
- return false;
-
- // Space before { (including space within '{ {').
- if (Right.is(tok::l_brace))
- return true;
-
- // Spaces inside braces.
- if (Left.is(tok::l_brace) && Right.isNot(tok::r_brace))
- return true;
-
- if (Left.isNot(tok::l_brace) && Right.is(tok::r_brace))
- return true;
-
- // Spaces around '=>'.
- if (Left.is(TT_FatArrow) || Right.is(TT_FatArrow))
- return true;
-
- // No spaces around attribute target colons
- if (Left.is(TT_AttributeColon) || Right.is(TT_AttributeColon))
- return false;
-
- // space between type and variable e.g. Dictionary<string,string> foo;
- if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
- return true;
-
- // spaces inside square brackets.
- if (Left.is(tok::l_square) || Right.is(tok::r_square))
- return Style.SpacesInSquareBrackets;
-
- // No space before ? in nullable types.
- if (Right.is(TT_CSharpNullable))
- return false;
-
- // No space before null forgiving '!'.
- if (Right.is(TT_NonNullAssertion))
- return false;
-
- // No space between consecutive commas '[,,]'.
- if (Left.is(tok::comma) && Right.is(tok::comma))
- return false;
-
- // space after var in `var (key, value)`
- if (Left.is(Keywords.kw_var) && Right.is(tok::l_paren))
- return true;
-
- // space between keywords and paren e.g. "using ("
- if (Right.is(tok::l_paren))
- if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when,
- Keywords.kw_lock))
- return Style.SpaceBeforeParensOptions.AfterControlStatements ||
- spaceRequiredBeforeParens(Right);
-
- // space between method modifier and opening parenthesis of a tuple return
- // type
- if (Left.isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
- tok::kw_virtual, tok::kw_extern, tok::kw_static,
- Keywords.kw_internal, Keywords.kw_abstract,
- Keywords.kw_sealed, Keywords.kw_override,
- Keywords.kw_async, Keywords.kw_unsafe) &&
- Right.is(tok::l_paren))
- return true;
- } else if (Style.isJavaScript()) {
- if (Left.is(TT_FatArrow))
- return true;
- // for await ( ...
- if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous &&
- Left.Previous->is(tok::kw_for))
- return true;
- if (Left.is(Keywords.kw_async) && Right.is(tok::l_paren) &&
- Right.MatchingParen) {
- const FormatToken *Next = Right.MatchingParen->getNextNonComment();
- // An async arrow function, for example: `x = async () => foo();`,
- // as opposed to calling a function called async: `x = async();`
- if (Next && Next->is(TT_FatArrow))
- return true;
- }
- if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
- (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
- return false;
- // In tagged template literals ("html`bar baz`"), there is no space between
- // the tag identifier and the template string.
- if (Keywords.IsJavaScriptIdentifier(Left,
- /* AcceptIdentifierName= */ false) &&
- Right.is(TT_TemplateString))
- return false;
- if (Right.is(tok::star) &&
- Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
- return false;
- if (Right.isOneOf(tok::l_brace, tok::l_square) &&
- Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
- Keywords.kw_extends, Keywords.kw_implements))
- return true;
- if (Right.is(tok::l_paren)) {
- // JS methods can use some keywords as names (e.g. `delete()`).
- if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo())
- return false;
- // Valid JS method names can include keywords, e.g. `foo.delete()` or
- // `bar.instanceof()`. Recognize call positions by preceding period.
- if (Left.Previous && Left.Previous->is(tok::period) &&
- Left.Tok.getIdentifierInfo())
- return false;
- // Additional unary JavaScript operators that need a space after.
- if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof,
- tok::kw_void))
- return true;
- }
- // `foo as const;` casts into a const type.
- if (Left.endsSequence(tok::kw_const, Keywords.kw_as))
- return false;
- if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
- tok::kw_const) ||
- // "of" is only a keyword if it appears after another identifier
- // (e.g. as "const x of y" in a for loop), or after a destructuring
- // operation (const [x, y] of z, const {a, b} of c).
- (Left.is(Keywords.kw_of) && Left.Previous &&
- (Left.Previous->is(tok::identifier) ||
- Left.Previous->isOneOf(tok::r_square, tok::r_brace)))) &&
- (!Left.Previous || !Left.Previous->is(tok::period)))
- return true;
- if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous &&
- Left.Previous->is(tok::period) && Right.is(tok::l_paren))
- return false;
- if (Left.is(Keywords.kw_as) &&
- Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren))
- return true;
- if (Left.is(tok::kw_default) && Left.Previous &&
- Left.Previous->is(tok::kw_export))
- return true;
- if (Left.is(Keywords.kw_is) && Right.is(tok::l_brace))
- return true;
- if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion))
- return false;
- if (Left.is(TT_JsTypeOperator) || Right.is(TT_JsTypeOperator))
- return false;
- if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
- Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
- return false;
- if (Left.is(tok::ellipsis))
- return false;
- if (Left.is(TT_TemplateCloser) &&
- !Right.isOneOf(tok::equal, tok::l_brace, tok::comma, tok::l_square,
- Keywords.kw_implements, Keywords.kw_extends))
- // Type assertions ('<type>expr') are not followed by whitespace. Other
- // locations that should have whitespace following are identified by the
- // above set of follower tokens.
- return false;
- if (Right.is(TT_NonNullAssertion))
- return false;
- if (Left.is(TT_NonNullAssertion) &&
- Right.isOneOf(Keywords.kw_as, Keywords.kw_in))
- return true; // "x! as string", "x! in y"
- } else if (Style.Language == FormatStyle::LK_Java) {
- if (Left.is(tok::r_square) && Right.is(tok::l_brace))
- return true;
- if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren))
- return Style.SpaceBeforeParensOptions.AfterControlStatements ||
- spaceRequiredBeforeParens(Right);
- if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private,
- tok::kw_protected) ||
- Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract,
- Keywords.kw_native)) &&
- Right.is(TT_TemplateOpener))
- return true;
- }
- if (Left.is(TT_ImplicitStringLiteral))
- return Right.hasWhitespaceBefore();
- if (Line.Type == LT_ObjCMethodDecl) {
- if (Left.is(TT_ObjCMethodSpecifier))
- return true;
- if (Left.is(tok::r_paren) && canBeObjCSelectorComponent(Right))
- // Don't space between ')' and <id> or ')' and 'new'. 'new' is not a
- // keyword in Objective-C, and '+ (instancetype)new;' is a standard class
- // method declaration.
- return false;
- }
- if (Line.Type == LT_ObjCProperty &&
- (Right.is(tok::equal) || Left.is(tok::equal)))
- return false;
-
- if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
- Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow))
- return true;
- if (Left.is(tok::comma) && !Right.is(TT_OverloadedOperatorLParen))
- return true;
- if (Right.is(tok::comma))
- return false;
- if (Right.is(TT_ObjCBlockLParen))
- return true;
- if (Right.is(TT_CtorInitializerColon))
- return Style.SpaceBeforeCtorInitializerColon;
- if (Right.is(TT_InheritanceColon) && !Style.SpaceBeforeInheritanceColon)
- return false;
- if (Right.is(TT_RangeBasedForLoopColon) &&
- !Style.SpaceBeforeRangeBasedForLoopColon)
- return false;
- if (Left.is(TT_BitFieldColon))
- return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both ||
- Style.BitFieldColonSpacing == FormatStyle::BFCS_After;
- if (Right.is(tok::colon)) {
- if (Line.First->isOneOf(tok::kw_default, tok::kw_case))
- return Style.SpaceBeforeCaseColon;
- const FormatToken *Next = Right.getNextNonComment();
- if (!Next || Next->is(tok::semi))
- return false;
- if (Right.is(TT_ObjCMethodExpr))
- return false;
- if (Left.is(tok::question))
- return false;
- if (Right.is(TT_InlineASMColon) && Left.is(tok::coloncolon))
- return false;
- if (Right.is(TT_DictLiteral))
- return Style.SpacesInContainerLiterals;
- if (Right.is(TT_AttributeColon))
- return false;
- if (Right.is(TT_CSharpNamedArgumentColon))
- return false;
- if (Right.is(TT_BitFieldColon))
- return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both ||
- Style.BitFieldColonSpacing == FormatStyle::BFCS_Before;
- return true;
- }
- // Do not merge "- -" into "--".
- if ((Left.isOneOf(tok::minus, tok::minusminus) &&
- Right.isOneOf(tok::minus, tok::minusminus)) ||
- (Left.isOneOf(tok::plus, tok::plusplus) &&
- Right.isOneOf(tok::plus, tok::plusplus)))
- return true;
- if (Left.is(TT_UnaryOperator)) {
- if (!Right.is(tok::l_paren)) {
- // The alternative operators for ~ and ! are "compl" and "not".
- // If they are used instead, we do not want to combine them with
- // the token to the right, unless that is a left paren.
- if (Left.is(tok::exclaim) && Left.TokenText == "not")
- return true;
- if (Left.is(tok::tilde) && Left.TokenText == "compl")
- return true;
- // Lambda captures allow for a lone &, so "&]" needs to be properly
- // handled.
- if (Left.is(tok::amp) && Right.is(tok::r_square))
- return Style.SpacesInSquareBrackets;
- }
- return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) ||
- Right.is(TT_BinaryOperator);
- }
-
- // If the next token is a binary operator or a selector name, we have
- // incorrectly classified the parenthesis as a cast. FIXME: Detect correctly.
- if (Left.is(TT_CastRParen))
- return Style.SpaceAfterCStyleCast ||
- Right.isOneOf(TT_BinaryOperator, TT_SelectorName);
-
- auto ShouldAddSpacesInAngles = [this, &Right]() {
- if (this->Style.SpacesInAngles == FormatStyle::SIAS_Always)
- return true;
- if (this->Style.SpacesInAngles == FormatStyle::SIAS_Leave)
- return Right.hasWhitespaceBefore();
- return false;
- };
-
- if (Left.is(tok::greater) && Right.is(tok::greater)) {
- if (Style.Language == FormatStyle::LK_TextProto ||
- (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral)))
- return !Style.Cpp11BracedListStyle;
- return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
- ((Style.Standard < FormatStyle::LS_Cpp11) ||
- ShouldAddSpacesInAngles());
- }
- if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
- Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
- (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod)))
- return false;
- if (!Style.SpaceBeforeAssignmentOperators && Left.isNot(TT_TemplateCloser) &&
- Right.getPrecedence() == prec::Assignment)
- return false;
- if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) &&
- (Left.is(tok::identifier) || Left.is(tok::kw_this)))
- return false;
- if (Right.is(tok::coloncolon) && Left.is(tok::identifier))
- // Generally don't remove existing spaces between an identifier and "::".
- // The identifier might actually be a macro name such as ALWAYS_INLINE. If
- // this turns out to be too lenient, add analysis of the identifier itself.
- return Right.hasWhitespaceBefore();
- if (Right.is(tok::coloncolon) &&
- !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren))
- // Put a space between < and :: in vector< ::std::string >
- return (Left.is(TT_TemplateOpener) &&
- ((Style.Standard < FormatStyle::LS_Cpp11) ||
- ShouldAddSpacesInAngles())) ||
- !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
- tok::kw___super, TT_TemplateOpener,
- TT_TemplateCloser)) ||
- (Left.is(tok::l_paren) && Style.SpacesInParentheses);
- if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
- return ShouldAddSpacesInAngles();
- // Space before TT_StructuredBindingLSquare.
- if (Right.is(TT_StructuredBindingLSquare))
- return !Left.isOneOf(tok::amp, tok::ampamp) ||
- getTokenReferenceAlignment(Left) != FormatStyle::PAS_Right;
- // Space before & or && following a TT_StructuredBindingLSquare.
- if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) &&
- Right.isOneOf(tok::amp, tok::ampamp))
- return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left;
- if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
- (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
- !Right.is(tok::r_paren)))
- return true;
- if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) &&
- Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen))
- return false;
- if (Right.is(tok::less) && Left.isNot(tok::l_paren) &&
- Line.startsWith(tok::hash))
- return true;
- if (Right.is(TT_TrailingUnaryOperator))
- return false;
- if (Left.is(TT_RegexLiteral))
- return false;
- return spaceRequiredBetween(Line, Left, Right);
-}
-
// Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style.
static bool isAllmanBrace(const FormatToken &Tok) {
return Tok.is(tok::l_brace) && Tok.is(BK_Block) &&
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits