2013-01-30 05:01:14 +08:00
|
|
|
//===--- TokenAnnotator.cpp - Format C++ code -----------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
2018-05-09 09:00:01 +08:00
|
|
|
/// This file implements a token annotator, i.e. creates
|
2013-01-30 05:01:14 +08:00
|
|
|
/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "TokenAnnotator.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
2015-05-06 16:38:24 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2013-04-09 04:33:42 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2014-04-22 06:55:36 +08:00
|
|
|
#define DEBUG_TYPE "format-token-annotator"
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace format {
|
|
|
|
|
2013-07-01 12:03:19 +08:00
|
|
|
namespace {
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Returns \c true if the token can be used as an identifier in
|
2018-04-28 02:51:12 +08:00
|
|
|
/// an Objective-C \c @selector, \c false otherwise.
|
|
|
|
///
|
|
|
|
/// Because getFormattingLangOpts() always lexes source code as
|
|
|
|
/// Objective-C++, C++ keywords like \c new and \c delete are
|
|
|
|
/// lexed as tok::kw_*, not tok::identifier, even for Objective-C.
|
|
|
|
///
|
|
|
|
/// For Objective-C and Objective-C++, both identifiers and keywords
|
|
|
|
/// are valid inside @selector(...) (or a macro which
|
|
|
|
/// invokes @selector(...)). So, we allow treat any identifier or
|
|
|
|
/// keyword as a potential Objective-C selector component.
|
|
|
|
static bool canBeObjCSelectorComponent(const FormatToken &Tok) {
|
|
|
|
return Tok.Tok.getIdentifierInfo() != nullptr;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// A parser that gathers additional information about tokens.
|
2013-01-30 05:01:14 +08:00
|
|
|
///
|
2013-03-13 00:28:18 +08:00
|
|
|
/// The \c TokenAnnotator tries to match parenthesis and square brakets and
|
2013-01-30 05:01:14 +08:00
|
|
|
/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
|
|
|
|
/// into template parameter lists.
|
|
|
|
class AnnotatingParser {
|
|
|
|
public:
|
clang-format: Add column layout formatting for braced lists
With this patch, braced lists (with more than 3 elements are formatted in a
column layout if possible). E.g.:
static const uint16_t CallerSavedRegs64Bit[] = {
X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,
X86::R8, X86::R9, X86::R10, X86::R11, 0
};
Required other changes:
- FormatTokens can now have a special role that contains extra data and can do
special formattings. A comma separated list is currently the only
implementation.
- Move penalty calculation entirely into ContinuationIndenter (there was a last
piece still in UnwrappedLineFormatter).
Review: http://llvm-reviews.chandlerc.com/D1457
llvm-svn: 189018
2013-08-22 23:00:41 +08:00
|
|
|
AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line,
|
2014-11-04 20:41:02 +08:00
|
|
|
const AdditionalKeywords &Keywords)
|
2014-11-24 00:46:28 +08:00
|
|
|
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
|
|
|
|
Keywords(Keywords) {
|
2013-06-26 08:30:14 +08:00
|
|
|
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
|
2014-03-18 19:22:45 +08:00
|
|
|
resetTokenMetadata(CurrentToken);
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
Formatter: Correctly format stars in `sizeof(int**)` and similar places.
This redoes how '*' and '&' are classified as pointer / reference markers when
followed by ')', '>', or ','.
Previously, determineStarAmpUsage() marked a single '*' and '&' followed by
')', '>', or ',' as pointer or reference marker. Now, all '*'s and '&'s
preceding ')', '>', or ',' are marked as pointer / reference markers. Fixes
PR14884.
Since only the last '*' in 'int ***' was marked as pointer before (the rest
were unary operators, which don't reach spaceRequiredBetween()),
spaceRequiredBetween() now had to be thought about handing multiple '*'s in
sequence.
Before:
return sizeof(int * *);
Type **A = static_cast<Type * *>(P);
Now:
return sizeof(int**);
Type **A = static_cast<Type **>(P);
While here, also make all methods of AnnotatingParser except parseLine()
private.
Review URL: http://llvm-reviews.chandlerc.com/D384
llvm-svn: 174975
2013-02-13 00:17:07 +08:00
|
|
|
private:
|
2013-01-30 05:01:14 +08:00
|
|
|
bool parseAngle() {
|
2016-02-05 22:17:16 +08:00
|
|
|
if (!CurrentToken || !CurrentToken->Previous)
|
|
|
|
return false;
|
|
|
|
if (NonTemplateLess.count(CurrentToken->Previous))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2016-02-05 22:17:16 +08:00
|
|
|
|
2017-09-28 01:57:50 +08:00
|
|
|
const FormatToken &Previous = *CurrentToken->Previous; // The '<'.
|
2016-02-05 22:17:16 +08:00
|
|
|
if (Previous.Previous) {
|
|
|
|
if (Previous.Previous->Tok.isLiteral())
|
|
|
|
return false;
|
|
|
|
if (Previous.Previous->is(tok::r_paren) && Contexts.size() > 1 &&
|
|
|
|
(!Previous.Previous->MatchingParen ||
|
|
|
|
!Previous.Previous->MatchingParen->is(TT_OverloadedOperatorLParen)))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Left = CurrentToken->Previous;
|
2015-05-04 15:39:00 +08:00
|
|
|
Left->ParentBracket = Contexts.back().ContextKind;
|
2016-02-11 14:43:01 +08:00
|
|
|
ScopedContextCreator ContextCreator(*this, tok::less, 12);
|
2015-05-06 22:53:50 +08:00
|
|
|
|
|
|
|
// If this angle is in the context of an expression, we need to be more
|
2015-05-07 22:19:59 +08:00
|
|
|
// hesitant to detect it as opening template parameters.
|
2015-05-06 22:53:50 +08:00
|
|
|
bool InExprContext = Contexts.back().IsExpression;
|
|
|
|
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().IsExpression = false;
|
2014-03-27 19:17:36 +08:00
|
|
|
// If there's a template keyword before the opening angle bracket, this is a
|
|
|
|
// template parameter, not an argument.
|
|
|
|
Contexts.back().InTemplateArgument =
|
2014-05-09 16:15:10 +08:00
|
|
|
Left->Previous && Left->Previous->Tok.isNot(tok::kw_template);
|
2014-03-27 19:17:36 +08:00
|
|
|
|
2014-10-21 17:57:09 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Java &&
|
|
|
|
CurrentToken->is(tok::question))
|
|
|
|
next();
|
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-01-30 05:01:14 +08:00
|
|
|
if (CurrentToken->is(tok::greater)) {
|
|
|
|
Left->MatchingParen = CurrentToken;
|
|
|
|
CurrentToken->MatchingParen = Left;
|
2018-02-06 19:34:34 +08:00
|
|
|
// In TT_Proto, we must distignuish between:
|
|
|
|
// map<key, value>
|
|
|
|
// msg < item: data >
|
|
|
|
// msg: < item: data >
|
|
|
|
// In TT_TextProto, map<key, value> does not occur.
|
|
|
|
if (Style.Language == FormatStyle::LK_TextProto ||
|
|
|
|
(Style.Language == FormatStyle::LK_Proto && Left->Previous &&
|
|
|
|
Left->Previous->isOneOf(TT_SelectorName, TT_DictLiteral)))
|
|
|
|
CurrentToken->Type = TT_DictLiteral;
|
|
|
|
else
|
|
|
|
CurrentToken->Type = TT_TemplateCloser;
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
|
|
|
return true;
|
|
|
|
}
|
2014-11-03 05:52:57 +08:00
|
|
|
if (CurrentToken->is(tok::question) &&
|
2014-11-14 16:22:46 +08:00
|
|
|
Style.Language == FormatStyle::LK_Java) {
|
|
|
|
next();
|
|
|
|
continue;
|
|
|
|
}
|
2015-05-06 22:53:50 +08:00
|
|
|
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
|
2017-06-27 21:43:07 +08:00
|
|
|
(CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
|
2017-07-03 23:05:14 +08:00
|
|
|
Style.Language != FormatStyle::LK_Proto &&
|
|
|
|
Style.Language != FormatStyle::LK_TextProto))
|
2013-05-15 21:46:48 +08:00
|
|
|
return false;
|
2013-06-02 02:56:00 +08:00
|
|
|
// If a && or || is found and interpreted as a binary operator, this set
|
2013-06-04 00:16:41 +08:00
|
|
|
// of angles is likely part of something like "a < b && c > d". If the
|
2013-06-02 02:56:00 +08:00
|
|
|
// angles are inside an expression, the ||/&& might also be a binary
|
|
|
|
// operator that was misinterpreted because we are parsing template
|
|
|
|
// parameters.
|
|
|
|
// FIXME: This is getting out of hand, write a decent parser.
|
2013-05-29 22:47:47 +08:00
|
|
|
if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) &&
|
2014-11-25 18:05:17 +08:00
|
|
|
CurrentToken->Previous->is(TT_BinaryOperator) &&
|
2014-07-28 21:19:58 +08:00
|
|
|
Contexts[Contexts.size() - 2].IsExpression &&
|
2015-06-17 17:43:56 +08:00
|
|
|
!Line.startsWith(tok::kw_template))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2013-02-14 23:01:34 +08:00
|
|
|
updateParameterCount(Left, CurrentToken);
|
2017-06-27 21:43:07 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Proto) {
|
|
|
|
if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) {
|
|
|
|
if (CurrentToken->is(tok::colon) ||
|
|
|
|
(CurrentToken->isOneOf(tok::l_brace, tok::less) &&
|
|
|
|
Previous->isNot(tok::colon)))
|
|
|
|
Previous->Type = TT_SelectorName;
|
|
|
|
}
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
if (!consumeToken())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parseParens(bool LookForDecls = false) {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!CurrentToken)
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2015-05-04 15:39:00 +08:00
|
|
|
FormatToken *Left = CurrentToken->Previous;
|
|
|
|
Left->ParentBracket = Contexts.back().ContextKind;
|
2013-03-14 21:45:21 +08:00
|
|
|
ScopedContextCreator ContextCreator(*this, tok::l_paren, 1);
|
2013-02-06 18:05:46 +08:00
|
|
|
|
|
|
|
// FIXME: This is a bit of a hack. Do better.
|
|
|
|
Contexts.back().ColonIsForRangeExpr =
|
|
|
|
Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
bool StartsObjCMethodExpr = false;
|
2018-03-12 23:42:40 +08:00
|
|
|
if (FormatToken *MaybeSel = Left->Previous) {
|
2013-01-30 05:01:14 +08:00
|
|
|
// @selector( starts a selector.
|
2013-05-29 22:47:47 +08:00
|
|
|
if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous &&
|
|
|
|
MaybeSel->Previous->is(tok::at)) {
|
2013-01-30 05:01:14 +08:00
|
|
|
StartsObjCMethodExpr = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-11 20:55:33 +08:00
|
|
|
if (Left->is(TT_OverloadedOperatorLParen)) {
|
|
|
|
Contexts.back().IsExpression = false;
|
2016-06-24 03:52:32 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript &&
|
2017-06-07 20:53:22 +08:00
|
|
|
(Line.startsWith(Keywords.kw_type, tok::identifier) ||
|
|
|
|
Line.startsWith(tok::kw_export, Keywords.kw_type,
|
|
|
|
tok::identifier))) {
|
2016-06-24 03:52:32 +08:00
|
|
|
// type X = (...);
|
2017-06-07 20:53:22 +08:00
|
|
|
// export type X = (...);
|
2016-06-24 03:52:32 +08:00
|
|
|
Contexts.back().IsExpression = false;
|
2016-01-11 20:55:33 +08:00
|
|
|
} else if (Left->Previous &&
|
2017-09-20 17:51:03 +08:00
|
|
|
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
|
|
|
|
tok::kw_if, tok::kw_while, tok::l_paren,
|
|
|
|
tok::comma) ||
|
|
|
|
Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) ||
|
|
|
|
Left->Previous->is(TT_BinaryOperator))) {
|
2013-10-21 02:15:30 +08:00
|
|
|
// static_assert, if and while usually contain expressions.
|
2013-08-02 01:58:23 +08:00
|
|
|
Contexts.back().IsExpression = true;
|
2016-03-22 01:57:31 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous &&
|
2016-06-10 06:49:04 +08:00
|
|
|
(Left->Previous->is(Keywords.kw_function) ||
|
|
|
|
(Left->Previous->endsSequence(tok::identifier,
|
|
|
|
Keywords.kw_function)))) {
|
|
|
|
// function(...) or function f(...)
|
2016-03-22 01:57:31 +08:00
|
|
|
Contexts.back().IsExpression = false;
|
2016-06-24 03:52:32 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous &&
|
|
|
|
Left->Previous->is(TT_JsTypeColon)) {
|
|
|
|
// let x: (SomeType);
|
|
|
|
Contexts.back().IsExpression = false;
|
2013-10-21 02:15:30 +08:00
|
|
|
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
|
|
|
|
Left->Previous->MatchingParen &&
|
2014-11-25 18:05:17 +08:00
|
|
|
Left->Previous->MatchingParen->is(TT_LambdaLSquare)) {
|
2013-10-21 02:15:30 +08:00
|
|
|
// This is a parameter list of a lambda expression.
|
|
|
|
Contexts.back().IsExpression = false;
|
2015-05-12 18:20:32 +08:00
|
|
|
} else if (Line.InPPDirective &&
|
2016-01-11 20:55:33 +08:00
|
|
|
(!Left->Previous || !Left->Previous->is(tok::identifier))) {
|
2015-05-12 18:20:32 +08:00
|
|
|
Contexts.back().IsExpression = true;
|
2014-03-27 17:43:54 +08:00
|
|
|
} else if (Contexts[Contexts.size() - 2].CaretFound) {
|
2013-12-23 15:29:06 +08:00
|
|
|
// This is the parameter list of an ObjC block.
|
|
|
|
Contexts.back().IsExpression = false;
|
2014-01-29 04:13:43 +08:00
|
|
|
} else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) {
|
|
|
|
Left->Type = TT_AttributeParen;
|
2015-05-04 17:22:29 +08:00
|
|
|
} else if (Left->Previous && Left->Previous->is(TT_ForEachMacro)) {
|
2014-04-01 20:55:11 +08:00
|
|
|
// The first argument to a foreach macro is a declaration.
|
|
|
|
Contexts.back().IsForEachMacro = true;
|
|
|
|
Contexts.back().IsExpression = false;
|
2014-10-21 15:57:50 +08:00
|
|
|
} else if (Left->Previous && Left->Previous->MatchingParen &&
|
2014-11-25 18:05:17 +08:00
|
|
|
Left->Previous->MatchingParen->is(TT_ObjCBlockLParen)) {
|
2014-10-21 15:57:50 +08:00
|
|
|
Contexts.back().IsExpression = false;
|
2015-12-28 15:44:25 +08:00
|
|
|
} else if (!Line.MustBeDeclaration && !Line.InPPDirective) {
|
|
|
|
bool IsForOrCatch =
|
|
|
|
Left->Previous && Left->Previous->isOneOf(tok::kw_for, tok::kw_catch);
|
|
|
|
Contexts.back().IsExpression = !IsForOrCatch;
|
2013-10-21 02:15:30 +08:00
|
|
|
}
|
2013-08-02 01:58:23 +08:00
|
|
|
|
2013-02-06 18:05:46 +08:00
|
|
|
if (StartsObjCMethodExpr) {
|
|
|
|
Contexts.back().ColonIsObjCMethodExpr = true;
|
|
|
|
Left->Type = TT_ObjCMethodExpr;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2018-03-12 23:42:40 +08:00
|
|
|
// MightBeFunctionType and ProbablyFunctionType are used for
|
|
|
|
// function pointer and reference types as well as Objective-C
|
|
|
|
// block types:
|
|
|
|
//
|
|
|
|
// void (*FunctionPointer)(void);
|
|
|
|
// void (&FunctionReference)(void);
|
|
|
|
// void (^ObjCBlock)(void);
|
2016-06-13 15:49:35 +08:00
|
|
|
bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
|
2018-03-12 23:42:40 +08:00
|
|
|
bool ProbablyFunctionType =
|
|
|
|
CurrentToken->isOneOf(tok::star, tok::amp, tok::caret);
|
2013-07-10 22:02:49 +08:00
|
|
|
bool HasMultipleLines = false;
|
|
|
|
bool HasMultipleParametersOnALine = false;
|
2015-04-15 15:26:18 +08:00
|
|
|
bool MightBeObjCForRangeLoop =
|
|
|
|
Left->Previous && Left->Previous->is(tok::kw_for);
|
2018-03-07 01:21:42 +08:00
|
|
|
FormatToken *PossibleObjCForInToken = nullptr;
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-01-30 05:01:14 +08:00
|
|
|
// LookForDecls is set when "if (" has been seen. Check for
|
|
|
|
// 'identifier' '*' 'identifier' followed by not '=' -- this
|
|
|
|
// '*' has to be a binary operator but determineStarAmpUsage() will
|
|
|
|
// categorize it as an unary operator, so set the right type here.
|
2013-05-29 22:47:47 +08:00
|
|
|
if (LookForDecls && CurrentToken->Next) {
|
2013-07-04 22:47:51 +08:00
|
|
|
FormatToken *Prev = CurrentToken->getPreviousNonComment();
|
2013-06-08 00:02:52 +08:00
|
|
|
if (Prev) {
|
2013-07-04 22:47:51 +08:00
|
|
|
FormatToken *PrevPrev = Prev->getPreviousNonComment();
|
2013-06-08 00:02:52 +08:00
|
|
|
FormatToken *Next = CurrentToken->Next;
|
|
|
|
if (PrevPrev && PrevPrev->is(tok::identifier) &&
|
|
|
|
Prev->isOneOf(tok::star, tok::amp, tok::ampamp) &&
|
|
|
|
CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) {
|
|
|
|
Prev->Type = TT_BinaryOperator;
|
|
|
|
LookForDecls = false;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (CurrentToken->Previous->is(TT_PointerOrReference) &&
|
2013-08-12 20:16:34 +08:00
|
|
|
CurrentToken->Previous->Previous->isOneOf(tok::l_paren,
|
|
|
|
tok::coloncolon))
|
2016-06-13 15:49:35 +08:00
|
|
|
ProbablyFunctionType = true;
|
|
|
|
if (CurrentToken->is(tok::comma))
|
|
|
|
MightBeFunctionType = false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (CurrentToken->Previous->is(TT_BinaryOperator))
|
2014-06-30 21:44:47 +08:00
|
|
|
Contexts.back().IsExpression = true;
|
2013-01-30 05:01:14 +08:00
|
|
|
if (CurrentToken->is(tok::r_paren)) {
|
2016-06-13 15:49:35 +08:00
|
|
|
if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next &&
|
2013-07-16 19:37:21 +08:00
|
|
|
(CurrentToken->Next->is(tok::l_paren) ||
|
2016-06-13 15:49:35 +08:00
|
|
|
(CurrentToken->Next->is(tok::l_square) && Line.MustBeDeclaration)))
|
2018-03-12 23:42:40 +08:00
|
|
|
Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
|
|
|
|
: TT_FunctionTypeLParen;
|
2013-01-30 05:01:14 +08:00
|
|
|
Left->MatchingParen = CurrentToken;
|
|
|
|
CurrentToken->MatchingParen = Left;
|
|
|
|
|
2016-01-07 22:36:11 +08:00
|
|
|
if (CurrentToken->Next && CurrentToken->Next->is(tok::l_brace) &&
|
|
|
|
Left->Previous && Left->Previous->is(tok::l_paren)) {
|
|
|
|
// Detect the case where macros are used to generate lambdas or
|
|
|
|
// function bodies, e.g.:
|
|
|
|
// auto my_lambda = MARCO((Type *type, int i) { .. body .. });
|
|
|
|
for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) {
|
|
|
|
if (Tok->is(TT_BinaryOperator) &&
|
|
|
|
Tok->isOneOf(tok::star, tok::amp, tok::ampamp))
|
|
|
|
Tok->Type = TT_PointerOrReference;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-05 18:07:47 +08:00
|
|
|
if (StartsObjCMethodExpr) {
|
2013-02-06 18:05:46 +08:00
|
|
|
CurrentToken->Type = TT_ObjCMethodExpr;
|
2014-05-09 16:15:10 +08:00
|
|
|
if (Contexts.back().FirstObjCSelectorName) {
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
|
|
|
|
Contexts.back().LongestObjCSelectorName;
|
2013-02-05 18:07:47 +08:00
|
|
|
}
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left->is(TT_AttributeParen))
|
2014-01-29 04:13:43 +08:00
|
|
|
CurrentToken->Type = TT_AttributeParen;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left->Previous && Left->Previous->is(TT_JavaAnnotation))
|
2014-10-21 17:25:39 +08:00
|
|
|
CurrentToken->Type = TT_JavaAnnotation;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation))
|
2014-11-01 02:23:49 +08:00
|
|
|
CurrentToken->Type = TT_LeadingJavaAnnotation;
|
2014-01-29 04:13:43 +08:00
|
|
|
|
2013-07-10 22:02:49 +08:00
|
|
|
if (!HasMultipleLines)
|
|
|
|
Left->PackingKind = PPK_Inconclusive;
|
|
|
|
else if (HasMultipleParametersOnALine)
|
|
|
|
Left->PackingKind = PPK_BinPacked;
|
|
|
|
else
|
|
|
|
Left->PackingKind = PPK_OnePerLine;
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-13 22:41:29 +08:00
|
|
|
if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2015-04-15 15:26:18 +08:00
|
|
|
|
|
|
|
if (CurrentToken->is(tok::l_brace))
|
2014-01-19 15:46:32 +08:00
|
|
|
Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen
|
2013-07-10 22:02:49 +08:00
|
|
|
if (CurrentToken->is(tok::comma) && CurrentToken->Next &&
|
|
|
|
!CurrentToken->Next->HasUnescapedNewline &&
|
|
|
|
!CurrentToken->Next->isTrailingComment())
|
|
|
|
HasMultipleParametersOnALine = true;
|
2016-11-01 14:23:14 +08:00
|
|
|
if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) ||
|
|
|
|
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
|
|
|
|
!CurrentToken->is(tok::l_brace))
|
2014-03-11 17:29:46 +08:00
|
|
|
Contexts.back().IsExpression = false;
|
2018-03-07 01:21:42 +08:00
|
|
|
if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
|
2015-04-15 15:26:18 +08:00
|
|
|
MightBeObjCForRangeLoop = false;
|
2018-03-07 01:21:42 +08:00
|
|
|
if (PossibleObjCForInToken) {
|
|
|
|
PossibleObjCForInToken->Type = TT_Unknown;
|
|
|
|
PossibleObjCForInToken = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) {
|
|
|
|
PossibleObjCForInToken = CurrentToken;
|
|
|
|
PossibleObjCForInToken->Type = TT_ObjCForIn;
|
|
|
|
}
|
2015-05-13 20:54:30 +08:00
|
|
|
// When we discover a 'new', we set CanBeExpression to 'false' in order to
|
|
|
|
// parse the type correctly. Reset that after a comma.
|
|
|
|
if (CurrentToken->is(tok::comma))
|
|
|
|
Contexts.back().CanBeExpression = true;
|
2015-04-15 15:26:18 +08:00
|
|
|
|
2014-06-03 20:02:45 +08:00
|
|
|
FormatToken *Tok = CurrentToken;
|
2013-01-30 05:01:14 +08:00
|
|
|
if (!consumeToken())
|
|
|
|
return false;
|
2014-06-03 20:02:45 +08:00
|
|
|
updateParameterCount(Left, Tok);
|
2013-07-10 22:02:49 +08:00
|
|
|
if (CurrentToken && CurrentToken->HasUnescapedNewline)
|
|
|
|
HasMultipleLines = true;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-12 23:42:38 +08:00
|
|
|
bool isCpp11AttributeSpecifier(const FormatToken &Tok) {
|
|
|
|
if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square))
|
|
|
|
return false;
|
|
|
|
const FormatToken *AttrTok = Tok.Next->Next;
|
|
|
|
if (!AttrTok)
|
|
|
|
return false;
|
|
|
|
// C++17 '[[using ns: foo, bar(baz, blech)]]'
|
|
|
|
// We assume nobody will name an ObjC variable 'using'.
|
|
|
|
if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon))
|
|
|
|
return true;
|
|
|
|
if (AttrTok->isNot(tok::identifier))
|
|
|
|
return false;
|
|
|
|
while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) {
|
|
|
|
// ObjC message send. We assume nobody will use : in a C++11 attribute
|
|
|
|
// specifier parameter, although this is technically valid:
|
|
|
|
// [[foo(:)]]
|
|
|
|
if (AttrTok->is(tok::colon) ||
|
|
|
|
AttrTok->startsSequence(tok::identifier, tok::identifier))
|
|
|
|
return false;
|
|
|
|
if (AttrTok->is(tok::ellipsis))
|
|
|
|
return true;
|
|
|
|
AttrTok = AttrTok->Next;
|
|
|
|
}
|
|
|
|
return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square);
|
|
|
|
}
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
bool parseSquare() {
|
|
|
|
if (!CurrentToken)
|
|
|
|
return false;
|
|
|
|
|
2013-06-17 21:19:53 +08:00
|
|
|
// A '[' could be an index subscript (after an identifier or after
|
2013-02-10 10:08:05 +08:00
|
|
|
// ')' or ']'), it could be the start of an Objective-C method
|
2018-03-12 23:42:38 +08:00
|
|
|
// expression, it could the start of an Objective-C array literal,
|
|
|
|
// or it could be a C++ attribute specifier [[foo::bar]].
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Left = CurrentToken->Previous;
|
2015-05-04 15:39:00 +08:00
|
|
|
Left->ParentBracket = Contexts.back().ContextKind;
|
2013-07-04 22:47:51 +08:00
|
|
|
FormatToken *Parent = Left->getPreviousNonComment();
|
2016-11-11 05:49:25 +08:00
|
|
|
|
|
|
|
// Cases where '>' is followed by '['.
|
|
|
|
// In C++, this can happen either in array of templates (foo<int>[10])
|
|
|
|
// or when array is a nested template type (unique_ptr<type1<type2>[]>).
|
|
|
|
bool CppArrayTemplates =
|
2017-09-20 17:51:03 +08:00
|
|
|
Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) &&
|
2016-11-11 05:49:25 +08:00
|
|
|
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
|
|
|
|
Contexts.back().InTemplateArgument);
|
|
|
|
|
2018-03-12 23:42:38 +08:00
|
|
|
bool IsCpp11AttributeSpecifier = isCpp11AttributeSpecifier(*Left) ||
|
|
|
|
Contexts.back().InCpp11AttributeSpecifier;
|
|
|
|
|
2016-11-12 15:38:22 +08:00
|
|
|
bool StartsObjCMethodExpr =
|
2018-03-12 23:42:38 +08:00
|
|
|
!CppArrayTemplates && Style.isCpp() && !IsCpp11AttributeSpecifier &&
|
2014-11-25 18:05:17 +08:00
|
|
|
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
|
2018-04-03 22:07:11 +08:00
|
|
|
!CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
|
2014-11-25 18:05:17 +08:00
|
|
|
(!Parent ||
|
|
|
|
Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
|
|
|
|
tok::kw_return, tok::kw_throw) ||
|
|
|
|
Parent->isUnaryOperator() ||
|
[clang-format] Ensure ObjC selectors with 0 args are annotated correctly
Summary:
Previously, clang-format would incorrectly annotate 0-argument
Objective-C selector names as TT_TrailingAnnotation:
```
% echo "-(void)foo;" > /tmp/test.m
% ./bin/clang-format -debug /tmp/test.m
Language: Objective-C
----
Line(0, FSC=0): minus[T=68, OC=0] l_paren[T=68, OC=1] void[T=68, OC=2]
r_paren[T=68, OC=6] identifier[T=68, OC=7] semi[T=68, OC=10]
Line(0, FSC=0): eof[T=68, OC=0]
Run 0...
AnnotatedTokens(L=0):
M=0 C=0 T=ObjCMethodSpecifier S=1 B=0 BK=0 P=0 Name=minus L=1 PPK=2
FakeLParens= FakeRParens=0 Text='-'
M=0 C=1 T=Unknown S=1 B=0 BK=0 P=33 Name=l_paren L=3 PPK=2
FakeLParens= FakeRParens=0 Text='('
M=0 C=1 T=Unknown S=0 B=0 BK=0 P=140 Name=void L=7 PPK=2 FakeLParens=
FakeRParens=0 Text='void'
M=0 C=0 T=CastRParen S=0 B=0 BK=0 P=43 Name=r_paren L=8 PPK=2
FakeLParens= FakeRParens=0 Text=')'
M=0 C=1 T=TrailingAnnotation S=0 B=0 BK=0 P=120 Name=identifier L=11
PPK=2 FakeLParens= FakeRParens=0 Text='foo'
M=0 C=0 T=Unknown S=0 B=0 BK=0 P=23 Name=semi L=12 PPK=2 FakeLParens=
FakeRParens=0 Text=';'
```
This caused us to incorrectly indent 0-argument wrapped selectors
when Style.IndentWrappedFunctionNames was false, as we thought
the 0-argument ObjC selector name was actually a trailing
annotation (which is always indented).
This diff fixes the issue and adds tests.
Test Plan: New tests added. Confirmed tests failed before diff.
After diff, tests passed. Ran tests with:
% make -j12 FormatTests &&
./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper, jolesiak
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D44996
llvm-svn: 329297
2018-04-05 23:26:23 +08:00
|
|
|
// FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
|
2014-11-25 18:05:17 +08:00
|
|
|
Parent->isOneOf(TT_ObjCForIn, TT_CastRParen) ||
|
2013-05-29 22:47:47 +08:00
|
|
|
getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown);
|
2013-10-27 01:00:22 +08:00
|
|
|
bool ColonFound = false;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2015-05-28 15:21:50 +08:00
|
|
|
unsigned BindingIncrease = 1;
|
2017-09-27 08:58:45 +08:00
|
|
|
if (Left->isCppStructuredBinding(Style)) {
|
|
|
|
Left->Type = TT_StructuredBindingLSquare;
|
|
|
|
} else if (Left->is(TT_Unknown)) {
|
|
|
|
if (StartsObjCMethodExpr) {
|
2015-05-28 15:21:50 +08:00
|
|
|
Left->Type = TT_ObjCMethodExpr;
|
2018-03-12 23:42:38 +08:00
|
|
|
} else if (IsCpp11AttributeSpecifier) {
|
|
|
|
Left->Type = TT_AttributeSquare;
|
2015-05-29 14:19:49 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript && Parent &&
|
2015-06-02 22:20:08 +08:00
|
|
|
Contexts.back().ContextKind == tok::l_brace &&
|
2015-05-29 14:19:49 +08:00
|
|
|
Parent->isOneOf(tok::l_brace, tok::comma)) {
|
|
|
|
Left->Type = TT_JsComputedPropertyName;
|
2017-06-19 22:41:21 +08:00
|
|
|
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
|
|
|
|
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
|
|
|
|
Left->Type = TT_DesignatedInitializerLSquare;
|
2017-02-20 20:43:41 +08:00
|
|
|
} else if (CurrentToken->is(tok::r_square) && Parent &&
|
|
|
|
Parent->is(TT_TemplateCloser)) {
|
|
|
|
Left->Type = TT_ArraySubscriptLSquare;
|
2016-01-04 15:27:33 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Proto ||
|
2018-02-13 18:20:39 +08:00
|
|
|
Style.Language == FormatStyle::LK_TextProto) {
|
|
|
|
// Square braces in LK_Proto can either be message field attributes:
|
|
|
|
//
|
|
|
|
// optional Aaa aaa = 1 [
|
|
|
|
// (aaa) = aaa
|
|
|
|
// ];
|
|
|
|
//
|
2018-02-19 23:31:25 +08:00
|
|
|
// extensions 123 [
|
|
|
|
// (aaa) = aaa
|
|
|
|
// ];
|
|
|
|
//
|
2018-02-13 18:20:39 +08:00
|
|
|
// or text proto extensions (in options):
|
|
|
|
//
|
|
|
|
// option (Aaa.options) = {
|
|
|
|
// [type.type/type] {
|
|
|
|
// key: value
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
2018-02-15 23:30:22 +08:00
|
|
|
// or repeated fields (in options):
|
|
|
|
//
|
|
|
|
// option (Aaa.options) = {
|
|
|
|
// keys: [ 1, 2, 3 ]
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// In the first and the third case we want to spread the contents inside
|
|
|
|
// the square braces; in the second we want to keep them inline.
|
2018-02-13 18:20:39 +08:00
|
|
|
Left->Type = TT_ArrayInitializerLSquare;
|
|
|
|
if (!Left->endsSequence(tok::l_square, tok::numeric_constant,
|
2018-02-15 23:30:22 +08:00
|
|
|
tok::equal) &&
|
2018-02-19 23:31:25 +08:00
|
|
|
!Left->endsSequence(tok::l_square, tok::numeric_constant,
|
|
|
|
tok::identifier) &&
|
2018-02-15 23:30:22 +08:00
|
|
|
!Left->endsSequence(tok::l_square, tok::colon, TT_SelectorName)) {
|
2018-02-13 18:20:39 +08:00
|
|
|
Left->Type = TT_ProtoExtensionLSquare;
|
|
|
|
BindingIncrease = 10;
|
|
|
|
}
|
|
|
|
} else if (!CppArrayTemplates && Parent &&
|
|
|
|
Parent->isOneOf(TT_BinaryOperator, TT_TemplateCloser, tok::at,
|
|
|
|
tok::comma, tok::l_paren, tok::l_square,
|
|
|
|
tok::question, tok::colon, tok::kw_return,
|
|
|
|
// Should only be relevant to JavaScript:
|
|
|
|
tok::kw_default)) {
|
2015-05-28 15:21:50 +08:00
|
|
|
Left->Type = TT_ArrayInitializerLSquare;
|
|
|
|
} else {
|
|
|
|
BindingIncrease = 10;
|
|
|
|
Left->Type = TT_ArraySubscriptLSquare;
|
|
|
|
}
|
2013-02-06 18:05:46 +08:00
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2015-05-28 15:21:50 +08:00
|
|
|
ScopedContextCreator ContextCreator(*this, tok::l_square, BindingIncrease);
|
|
|
|
Contexts.back().IsExpression = true;
|
2017-08-08 23:00:58 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Parent &&
|
|
|
|
Parent->is(TT_JsTypeColon))
|
|
|
|
Contexts.back().IsExpression = false;
|
|
|
|
|
2015-05-28 15:21:50 +08:00
|
|
|
Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr;
|
2018-03-12 23:42:38 +08:00
|
|
|
Contexts.back().InCpp11AttributeSpecifier = IsCpp11AttributeSpecifier;
|
2015-05-28 15:21:50 +08:00
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-01-30 05:01:14 +08:00
|
|
|
if (CurrentToken->is(tok::r_square)) {
|
2018-03-12 23:42:38 +08:00
|
|
|
if (IsCpp11AttributeSpecifier)
|
|
|
|
CurrentToken->Type = TT_AttributeSquare;
|
|
|
|
else if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) &&
|
|
|
|
Left->is(TT_ObjCMethodExpr)) {
|
2013-02-06 14:20:11 +08:00
|
|
|
// An ObjC method call is rarely followed by an open parenthesis.
|
2013-01-30 05:01:14 +08:00
|
|
|
// FIXME: Do we incorrectly label ":" with this?
|
|
|
|
StartsObjCMethodExpr = false;
|
|
|
|
Left->Type = TT_Unknown;
|
|
|
|
}
|
2014-04-08 21:07:41 +08:00
|
|
|
if (StartsObjCMethodExpr && CurrentToken->Previous != Left) {
|
2013-02-06 18:05:46 +08:00
|
|
|
CurrentToken->Type = TT_ObjCMethodExpr;
|
2018-05-18 23:27:02 +08:00
|
|
|
// If we haven't seen a colon yet, make sure the last identifier
|
|
|
|
// before the r_square is tagged as a selector name component.
|
|
|
|
if (!ColonFound && CurrentToken->Previous &&
|
|
|
|
CurrentToken->Previous->is(TT_Unknown) &&
|
|
|
|
canBeObjCSelectorComponent(*CurrentToken->Previous))
|
|
|
|
CurrentToken->Previous->Type = TT_SelectorName;
|
2013-02-06 14:20:11 +08:00
|
|
|
// determineStarAmpUsage() thinks that '*' '[' is allocating an
|
|
|
|
// array of pointers, but if '[' starts a selector then '*' is a
|
|
|
|
// binary operator.
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Parent && Parent->is(TT_PointerOrReference))
|
2013-02-07 00:54:35 +08:00
|
|
|
Parent->Type = TT_BinaryOperator;
|
2013-02-04 15:21:18 +08:00
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
Left->MatchingParen = CurrentToken;
|
|
|
|
CurrentToken->MatchingParen = Left;
|
2014-05-09 16:15:10 +08:00
|
|
|
if (Contexts.back().FirstObjCSelectorName) {
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
|
|
|
|
Contexts.back().LongestObjCSelectorName;
|
2018-02-07 18:35:08 +08:00
|
|
|
Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts =
|
|
|
|
Left->ParameterCount;
|
2014-06-03 20:02:45 +08:00
|
|
|
if (Left->BlockParameterCount > 1)
|
2013-12-23 15:29:06 +08:00
|
|
|
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-13 22:41:29 +08:00
|
|
|
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2014-10-16 16:38:51 +08:00
|
|
|
if (CurrentToken->is(tok::colon)) {
|
2018-03-12 23:42:38 +08:00
|
|
|
if (IsCpp11AttributeSpecifier &&
|
|
|
|
CurrentToken->endsSequence(tok::colon, tok::identifier,
|
|
|
|
tok::kw_using)) {
|
|
|
|
// Remember that this is a [[using ns: foo]] C++ attribute, so we
|
|
|
|
// don't add a space before the colon (unlike other colons).
|
|
|
|
CurrentToken->Type = TT_AttributeColon;
|
|
|
|
} else if (Left->isOneOf(TT_ArraySubscriptLSquare,
|
|
|
|
TT_DesignatedInitializerLSquare)) {
|
2014-10-16 16:38:51 +08:00
|
|
|
Left->Type = TT_ObjCMethodExpr;
|
|
|
|
StartsObjCMethodExpr = true;
|
2018-02-07 18:35:08 +08:00
|
|
|
// ParameterCount might have been set to 1 before expression was
|
|
|
|
// recognized as ObjCMethodExpr (as '1 + number of commas' formula is
|
|
|
|
// used for other expression types). Parameter counter has to be,
|
|
|
|
// therefore, reset to 0.
|
|
|
|
Left->ParameterCount = 0;
|
2014-10-16 16:38:51 +08:00
|
|
|
Contexts.back().ColonIsObjCMethodExpr = true;
|
|
|
|
if (Parent && Parent->is(tok::r_paren))
|
[clang-format] Ensure ObjC selectors with 0 args are annotated correctly
Summary:
Previously, clang-format would incorrectly annotate 0-argument
Objective-C selector names as TT_TrailingAnnotation:
```
% echo "-(void)foo;" > /tmp/test.m
% ./bin/clang-format -debug /tmp/test.m
Language: Objective-C
----
Line(0, FSC=0): minus[T=68, OC=0] l_paren[T=68, OC=1] void[T=68, OC=2]
r_paren[T=68, OC=6] identifier[T=68, OC=7] semi[T=68, OC=10]
Line(0, FSC=0): eof[T=68, OC=0]
Run 0...
AnnotatedTokens(L=0):
M=0 C=0 T=ObjCMethodSpecifier S=1 B=0 BK=0 P=0 Name=minus L=1 PPK=2
FakeLParens= FakeRParens=0 Text='-'
M=0 C=1 T=Unknown S=1 B=0 BK=0 P=33 Name=l_paren L=3 PPK=2
FakeLParens= FakeRParens=0 Text='('
M=0 C=1 T=Unknown S=0 B=0 BK=0 P=140 Name=void L=7 PPK=2 FakeLParens=
FakeRParens=0 Text='void'
M=0 C=0 T=CastRParen S=0 B=0 BK=0 P=43 Name=r_paren L=8 PPK=2
FakeLParens= FakeRParens=0 Text=')'
M=0 C=1 T=TrailingAnnotation S=0 B=0 BK=0 P=120 Name=identifier L=11
PPK=2 FakeLParens= FakeRParens=0 Text='foo'
M=0 C=0 T=Unknown S=0 B=0 BK=0 P=23 Name=semi L=12 PPK=2 FakeLParens=
FakeRParens=0 Text=';'
```
This caused us to incorrectly indent 0-argument wrapped selectors
when Style.IndentWrappedFunctionNames was false, as we thought
the 0-argument ObjC selector name was actually a trailing
annotation (which is always indented).
This diff fixes the issue and adds tests.
Test Plan: New tests added. Confirmed tests failed before diff.
After diff, tests passed. Ran tests with:
% make -j12 FormatTests &&
./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper, jolesiak
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D44996
llvm-svn: 329297
2018-04-05 23:26:23 +08:00
|
|
|
// FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
|
2014-10-16 16:38:51 +08:00
|
|
|
Parent->Type = TT_CastRParen;
|
|
|
|
}
|
2013-10-27 01:00:22 +08:00
|
|
|
ColonFound = true;
|
2014-10-16 16:38:51 +08:00
|
|
|
}
|
2015-05-28 15:21:50 +08:00
|
|
|
if (CurrentToken->is(tok::comma) && Left->is(TT_ObjCMethodExpr) &&
|
|
|
|
!ColonFound)
|
2013-10-22 23:30:28 +08:00
|
|
|
Left->Type = TT_ArrayInitializerLSquare;
|
2015-01-10 07:25:06 +08:00
|
|
|
FormatToken *Tok = CurrentToken;
|
2013-01-30 05:01:14 +08:00
|
|
|
if (!consumeToken())
|
|
|
|
return false;
|
2014-06-03 20:02:45 +08:00
|
|
|
updateParameterCount(Left, Tok);
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parseBrace() {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (CurrentToken) {
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Left = CurrentToken->Previous;
|
2015-05-04 15:39:00 +08:00
|
|
|
Left->ParentBracket = Contexts.back().ContextKind;
|
2014-03-27 17:43:54 +08:00
|
|
|
|
|
|
|
if (Contexts.back().CaretFound)
|
|
|
|
Left->Type = TT_ObjCBlockLBrace;
|
|
|
|
Contexts.back().CaretFound = false;
|
|
|
|
|
2013-10-24 18:31:50 +08:00
|
|
|
ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
|
|
|
|
Contexts.back().ColonIsDictLiteral = true;
|
2014-05-22 17:00:33 +08:00
|
|
|
if (Left->BlockKind == BK_BracedInit)
|
|
|
|
Contexts.back().IsExpression = true;
|
2017-08-08 23:00:58 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous &&
|
|
|
|
Left->Previous->is(TT_JsTypeColon))
|
|
|
|
Contexts.back().IsExpression = false;
|
2013-05-26 13:39:26 +08:00
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-05-06 16:27:33 +08:00
|
|
|
if (CurrentToken->is(tok::r_brace)) {
|
|
|
|
Left->MatchingParen = CurrentToken;
|
|
|
|
CurrentToken->MatchingParen = Left;
|
|
|
|
next();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
|
|
|
|
return false;
|
|
|
|
updateParameterCount(Left, CurrentToken);
|
2017-06-27 21:43:07 +08:00
|
|
|
if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
|
2014-08-15 13:00:35 +08:00
|
|
|
FormatToken *Previous = CurrentToken->getPreviousNonComment();
|
2017-08-15 00:09:08 +08:00
|
|
|
if (Previous->is(TT_JsTypeOptionalQuestion))
|
|
|
|
Previous = Previous->getPreviousNonComment();
|
2018-01-25 22:10:43 +08:00
|
|
|
if ((CurrentToken->is(tok::colon) &&
|
|
|
|
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
|
|
|
|
Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) {
|
|
|
|
Left->Type = TT_DictLiteral;
|
|
|
|
if (Previous->Tok.getIdentifierInfo() ||
|
|
|
|
Previous->is(tok::string_literal))
|
|
|
|
Previous->Type = TT_SelectorName;
|
|
|
|
}
|
2015-04-04 15:56:55 +08:00
|
|
|
if (CurrentToken->is(tok::colon) ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript)
|
2014-08-15 13:00:35 +08:00
|
|
|
Left->Type = TT_DictLiteral;
|
2014-06-10 22:44:02 +08:00
|
|
|
}
|
2016-11-29 17:40:36 +08:00
|
|
|
if (CurrentToken->is(tok::comma) &&
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript)
|
|
|
|
Left->Type = TT_DictLiteral;
|
2013-05-06 16:27:33 +08:00
|
|
|
if (!consumeToken())
|
|
|
|
return false;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
}
|
2018-04-23 16:50:36 +08:00
|
|
|
return true;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
2013-02-20 20:56:39 +08:00
|
|
|
|
2013-05-29 22:47:47 +08:00
|
|
|
void updateParameterCount(FormatToken *Left, FormatToken *Current) {
|
2016-02-08 06:17:13 +08:00
|
|
|
if (Current->is(tok::l_brace) && Current->BlockKind == BK_Block)
|
2014-06-03 20:02:45 +08:00
|
|
|
++Left->BlockParameterCount;
|
2018-02-07 18:35:08 +08:00
|
|
|
if (Left->Type == TT_ObjCMethodExpr) {
|
|
|
|
if (Current->is(tok::colon))
|
|
|
|
++Left->ParameterCount;
|
|
|
|
} else if (Current->is(tok::comma)) {
|
2013-02-14 23:01:34 +08:00
|
|
|
++Left->ParameterCount;
|
clang-format: Add column layout formatting for braced lists
With this patch, braced lists (with more than 3 elements are formatted in a
column layout if possible). E.g.:
static const uint16_t CallerSavedRegs64Bit[] = {
X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,
X86::R8, X86::R9, X86::R10, X86::R11, 0
};
Required other changes:
- FormatTokens can now have a special role that contains extra data and can do
special formattings. A comma separated list is currently the only
implementation.
- Move penalty calculation entirely into ContinuationIndenter (there was a last
piece still in UnwrappedLineFormatter).
Review: http://llvm-reviews.chandlerc.com/D1457
llvm-svn: 189018
2013-08-22 23:00:41 +08:00
|
|
|
if (!Left->Role)
|
|
|
|
Left->Role.reset(new CommaSeparatedList(Style));
|
|
|
|
Left->Role->CommaFound(Current);
|
2013-07-10 22:02:49 +08:00
|
|
|
} else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) {
|
2013-02-14 23:01:34 +08:00
|
|
|
Left->ParameterCount = 1;
|
2013-07-10 22:02:49 +08:00
|
|
|
}
|
2013-02-14 23:01:34 +08:00
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
|
|
|
|
bool parseConditional() {
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-01-30 05:01:14 +08:00
|
|
|
if (CurrentToken->is(tok::colon)) {
|
|
|
|
CurrentToken->Type = TT_ConditionalExpr;
|
|
|
|
next();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!consumeToken())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parseTemplateDeclaration() {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (CurrentToken && CurrentToken->is(tok::less)) {
|
2013-01-30 05:01:14 +08:00
|
|
|
CurrentToken->Type = TT_TemplateOpener;
|
|
|
|
next();
|
|
|
|
if (!parseAngle())
|
|
|
|
return false;
|
2014-05-09 16:15:10 +08:00
|
|
|
if (CurrentToken)
|
2013-05-29 22:47:47 +08:00
|
|
|
CurrentToken->Previous->ClosesTemplateDeclaration = true;
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool consumeToken() {
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Tok = CurrentToken;
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
2013-05-29 22:47:47 +08:00
|
|
|
switch (Tok->Tok.getKind()) {
|
2013-01-30 05:01:14 +08:00
|
|
|
case tok::plus:
|
|
|
|
case tok::minus:
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!Tok->Previous && Line.MustBeDeclaration)
|
2013-01-30 05:01:14 +08:00
|
|
|
Tok->Type = TT_ObjCMethodSpecifier;
|
|
|
|
break;
|
|
|
|
case tok::colon:
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!Tok->Previous)
|
2013-03-18 20:50:26 +08:00
|
|
|
return false;
|
2013-01-30 05:01:14 +08:00
|
|
|
// Colons from ?: are handled in parseConditional().
|
2015-04-13 23:01:40 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
2015-05-05 16:40:32 +08:00
|
|
|
if (Contexts.back().ColonIsForRangeExpr || // colon in for loop
|
|
|
|
(Contexts.size() == 1 && // switch/case labels
|
2015-04-13 23:01:40 +08:00
|
|
|
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) ||
|
2015-05-05 16:40:32 +08:00
|
|
|
Contexts.back().ContextKind == tok::l_paren || // function params
|
|
|
|
Contexts.back().ContextKind == tok::l_square || // array type
|
2017-08-08 23:00:58 +08:00
|
|
|
(!Contexts.back().IsExpression &&
|
|
|
|
Contexts.back().ContextKind == tok::l_brace) || // object type
|
2015-06-03 16:43:18 +08:00
|
|
|
(Contexts.size() == 1 &&
|
|
|
|
Line.MustBeDeclaration)) { // method/property declaration
|
2017-08-02 01:19:32 +08:00
|
|
|
Contexts.back().IsExpression = false;
|
2015-04-13 23:01:40 +08:00
|
|
|
Tok->Type = TT_JsTypeColon;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-01-04 15:28:12 +08:00
|
|
|
if (Contexts.back().ColonIsDictLiteral ||
|
2017-07-03 23:05:14 +08:00
|
|
|
Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) {
|
2013-10-24 18:31:50 +08:00
|
|
|
Tok->Type = TT_DictLiteral;
|
2017-07-03 23:05:14 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_TextProto) {
|
|
|
|
if (FormatToken *Previous = Tok->getPreviousNonComment())
|
|
|
|
Previous->Type = TT_SelectorName;
|
|
|
|
}
|
2013-02-06 18:05:46 +08:00
|
|
|
} else if (Contexts.back().ColonIsObjCMethodExpr ||
|
2015-06-17 17:43:56 +08:00
|
|
|
Line.startsWith(TT_ObjCMethodSpecifier)) {
|
2013-01-30 05:01:14 +08:00
|
|
|
Tok->Type = TT_ObjCMethodExpr;
|
2016-11-12 15:38:22 +08:00
|
|
|
const FormatToken *BeforePrevious = Tok->Previous->Previous;
|
2018-06-29 23:26:37 +08:00
|
|
|
// Ensure we tag all identifiers in method declarations as
|
|
|
|
// TT_SelectorName.
|
|
|
|
bool UnknownIdentifierInMethodDeclaration =
|
|
|
|
Line.startsWith(TT_ObjCMethodSpecifier) &&
|
|
|
|
Tok->Previous->is(tok::identifier) && Tok->Previous->is(TT_Unknown);
|
2016-11-12 15:38:22 +08:00
|
|
|
if (!BeforePrevious ||
|
[clang-format] Ensure ObjC selectors with 0 args are annotated correctly
Summary:
Previously, clang-format would incorrectly annotate 0-argument
Objective-C selector names as TT_TrailingAnnotation:
```
% echo "-(void)foo;" > /tmp/test.m
% ./bin/clang-format -debug /tmp/test.m
Language: Objective-C
----
Line(0, FSC=0): minus[T=68, OC=0] l_paren[T=68, OC=1] void[T=68, OC=2]
r_paren[T=68, OC=6] identifier[T=68, OC=7] semi[T=68, OC=10]
Line(0, FSC=0): eof[T=68, OC=0]
Run 0...
AnnotatedTokens(L=0):
M=0 C=0 T=ObjCMethodSpecifier S=1 B=0 BK=0 P=0 Name=minus L=1 PPK=2
FakeLParens= FakeRParens=0 Text='-'
M=0 C=1 T=Unknown S=1 B=0 BK=0 P=33 Name=l_paren L=3 PPK=2
FakeLParens= FakeRParens=0 Text='('
M=0 C=1 T=Unknown S=0 B=0 BK=0 P=140 Name=void L=7 PPK=2 FakeLParens=
FakeRParens=0 Text='void'
M=0 C=0 T=CastRParen S=0 B=0 BK=0 P=43 Name=r_paren L=8 PPK=2
FakeLParens= FakeRParens=0 Text=')'
M=0 C=1 T=TrailingAnnotation S=0 B=0 BK=0 P=120 Name=identifier L=11
PPK=2 FakeLParens= FakeRParens=0 Text='foo'
M=0 C=0 T=Unknown S=0 B=0 BK=0 P=23 Name=semi L=12 PPK=2 FakeLParens=
FakeRParens=0 Text=';'
```
This caused us to incorrectly indent 0-argument wrapped selectors
when Style.IndentWrappedFunctionNames was false, as we thought
the 0-argument ObjC selector name was actually a trailing
annotation (which is always indented).
This diff fixes the issue and adds tests.
Test Plan: New tests added. Confirmed tests failed before diff.
After diff, tests passed. Ran tests with:
% make -j12 FormatTests &&
./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper, jolesiak
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D44996
llvm-svn: 329297
2018-04-05 23:26:23 +08:00
|
|
|
// FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
|
2016-11-12 15:38:22 +08:00
|
|
|
!(BeforePrevious->is(TT_CastRParen) ||
|
|
|
|
(BeforePrevious->is(TT_ObjCMethodExpr) &&
|
|
|
|
BeforePrevious->is(tok::colon))) ||
|
|
|
|
BeforePrevious->is(tok::r_square) ||
|
2018-06-29 23:26:37 +08:00
|
|
|
Contexts.back().LongestObjCSelectorName == 0 ||
|
|
|
|
UnknownIdentifierInMethodDeclaration) {
|
2016-11-12 15:38:22 +08:00
|
|
|
Tok->Previous->Type = TT_SelectorName;
|
|
|
|
if (!Contexts.back().FirstObjCSelectorName)
|
|
|
|
Contexts.back().FirstObjCSelectorName = Tok->Previous;
|
2018-02-09 23:41:56 +08:00
|
|
|
else if (Tok->Previous->ColumnWidth >
|
|
|
|
Contexts.back().LongestObjCSelectorName)
|
|
|
|
Contexts.back().LongestObjCSelectorName =
|
|
|
|
Tok->Previous->ColumnWidth;
|
2016-11-12 15:38:22 +08:00
|
|
|
}
|
2013-02-06 18:05:46 +08:00
|
|
|
} else if (Contexts.back().ColonIsForRangeExpr) {
|
2015-04-13 23:01:40 +08:00
|
|
|
Tok->Type = TT_RangeBasedForLoopColon;
|
2014-05-09 21:11:16 +08:00
|
|
|
} else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
|
2013-10-10 21:36:20 +08:00
|
|
|
Tok->Type = TT_BitFieldColon;
|
2014-05-28 18:09:11 +08:00
|
|
|
} else if (Contexts.size() == 1 &&
|
|
|
|
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
|
2016-10-20 22:58:45 +08:00
|
|
|
if (Tok->getPreviousNonComment()->isOneOf(tok::r_paren,
|
|
|
|
tok::kw_noexcept))
|
2015-02-19 01:09:53 +08:00
|
|
|
Tok->Type = TT_CtorInitializerColon;
|
|
|
|
else
|
|
|
|
Tok->Type = TT_InheritanceColon;
|
2018-04-28 02:51:12 +08:00
|
|
|
} else if (canBeObjCSelectorComponent(*Tok->Previous) && Tok->Next &&
|
2018-03-20 22:53:25 +08:00
|
|
|
(Tok->Next->isOneOf(tok::r_paren, tok::comma) ||
|
2018-04-28 02:51:12 +08:00
|
|
|
(canBeObjCSelectorComponent(*Tok->Next) && Tok->Next->Next &&
|
|
|
|
Tok->Next->Next->is(tok::colon)))) {
|
2014-10-20 20:01:45 +08:00
|
|
|
// This handles a special macro in ObjC code where selectors including
|
|
|
|
// the colon are passed as macro arguments.
|
|
|
|
Tok->Type = TT_ObjCMethodExpr;
|
2013-03-14 21:45:21 +08:00
|
|
|
} else if (Contexts.back().ContextKind == tok::l_paren) {
|
2015-04-13 23:01:40 +08:00
|
|
|
Tok->Type = TT_InlineASMColon;
|
2013-02-05 18:07:47 +08:00
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
break;
|
2016-03-22 01:57:31 +08:00
|
|
|
case tok::pipe:
|
|
|
|
case tok::amp:
|
|
|
|
// | and & in declarations/type expressions represent union and
|
|
|
|
// intersection types, respectively.
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
!Contexts.back().IsExpression)
|
|
|
|
Tok->Type = TT_JsTypeOperator;
|
|
|
|
break;
|
2013-01-30 05:01:14 +08:00
|
|
|
case tok::kw_if:
|
|
|
|
case tok::kw_while:
|
2017-09-20 17:51:03 +08:00
|
|
|
if (Tok->is(tok::kw_if) && CurrentToken &&
|
|
|
|
CurrentToken->is(tok::kw_constexpr))
|
2017-06-19 15:40:49 +08:00
|
|
|
next();
|
2014-05-09 16:15:10 +08:00
|
|
|
if (CurrentToken && CurrentToken->is(tok::l_paren)) {
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
2013-06-26 08:30:14 +08:00
|
|
|
if (!parseParens(/*LookForDecls=*/true))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case tok::kw_for:
|
2017-05-21 15:29:07 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
2017-11-25 17:24:33 +08:00
|
|
|
// x.for and {for: ...}
|
|
|
|
if ((Tok->Previous && Tok->Previous->is(tok::period)) ||
|
|
|
|
(Tok->Next && Tok->Next->is(tok::colon)))
|
2017-05-16 03:33:20 +08:00
|
|
|
break;
|
2017-05-19 05:19:29 +08:00
|
|
|
// JS' for await ( ...
|
|
|
|
if (CurrentToken && CurrentToken->is(Keywords.kw_await))
|
2017-05-16 03:33:20 +08:00
|
|
|
next();
|
2017-05-21 15:29:07 +08:00
|
|
|
}
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().ColonIsForRangeExpr = true;
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
|
|
|
if (!parseParens())
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case tok::l_paren:
|
2015-07-16 03:11:58 +08:00
|
|
|
// When faced with 'operator()()', the kw_operator handler incorrectly
|
|
|
|
// marks the first l_paren as a OverloadedOperatorLParen. Here, we make
|
|
|
|
// the first two parens OverloadedOperators and the second l_paren an
|
|
|
|
// OverloadedOperatorLParen.
|
2017-09-20 17:51:03 +08:00
|
|
|
if (Tok->Previous && Tok->Previous->is(tok::r_paren) &&
|
2015-07-16 03:11:58 +08:00
|
|
|
Tok->Previous->MatchingParen &&
|
|
|
|
Tok->Previous->MatchingParen->is(TT_OverloadedOperatorLParen)) {
|
|
|
|
Tok->Previous->Type = TT_OverloadedOperator;
|
|
|
|
Tok->Previous->MatchingParen->Type = TT_OverloadedOperator;
|
|
|
|
Tok->Type = TT_OverloadedOperatorLParen;
|
|
|
|
}
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
if (!parseParens())
|
|
|
|
return false;
|
2013-11-08 01:43:07 +08:00
|
|
|
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
|
2015-06-17 17:43:56 +08:00
|
|
|
!Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) &&
|
2015-01-14 17:47:57 +08:00
|
|
|
(!Tok->Previous ||
|
2015-07-06 19:30:34 +08:00
|
|
|
!Tok->Previous->isOneOf(tok::kw_decltype, tok::kw___attribute,
|
|
|
|
TT_LeadingJavaAnnotation)))
|
Allow breaking between a type and name in variable declarations.
This fixes llvm.org/PR14967 and is generall necessary to avoid
situations where the column limit is exceeded. The challenge is
restricting such lines splits, otherwise clang-format suddenly starts
breaking at bad places.
Before:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string,
SomeOtherTemplateParameter> &ReallyReallyLongParameterName,
const SomeType<string,
SomeOtherTemplateParameter> &AnotherLongParameterName) {}
After:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string, SomeOtherTemplateParameter> &
ReallyReallyLongParameterName,
const SomeType<string, SomeOtherTemplateParameter> &
AnotherLongParameterName) {}
llvm-svn: 175999
2013-02-25 02:54:32 +08:00
|
|
|
Line.MightBeFunctionDecl = true;
|
2013-01-30 05:01:14 +08:00
|
|
|
break;
|
|
|
|
case tok::l_square:
|
|
|
|
if (!parseSquare())
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case tok::l_brace:
|
2017-07-03 23:05:14 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_TextProto) {
|
2017-09-20 17:51:03 +08:00
|
|
|
FormatToken *Previous = Tok->getPreviousNonComment();
|
2017-07-03 23:05:14 +08:00
|
|
|
if (Previous && Previous->Type != TT_DictLiteral)
|
|
|
|
Previous->Type = TT_SelectorName;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
if (!parseBrace())
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case tok::less:
|
2016-02-05 22:17:16 +08:00
|
|
|
if (parseAngle()) {
|
2013-01-30 05:01:14 +08:00
|
|
|
Tok->Type = TT_TemplateOpener;
|
2018-02-06 19:34:34 +08:00
|
|
|
// In TT_Proto, we must distignuish between:
|
|
|
|
// map<key, value>
|
|
|
|
// msg < item: data >
|
|
|
|
// msg: < item: data >
|
|
|
|
// In TT_TextProto, map<key, value> does not occur.
|
|
|
|
if (Style.Language == FormatStyle::LK_TextProto ||
|
|
|
|
(Style.Language == FormatStyle::LK_Proto && Tok->Previous &&
|
|
|
|
Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) {
|
|
|
|
Tok->Type = TT_DictLiteral;
|
2017-07-03 23:05:14 +08:00
|
|
|
FormatToken *Previous = Tok->getPreviousNonComment();
|
|
|
|
if (Previous && Previous->Type != TT_DictLiteral)
|
|
|
|
Previous->Type = TT_SelectorName;
|
|
|
|
}
|
2015-01-08 16:48:21 +08:00
|
|
|
} else {
|
2013-01-30 05:01:14 +08:00
|
|
|
Tok->Type = TT_BinaryOperator;
|
2015-05-06 16:38:24 +08:00
|
|
|
NonTemplateLess.insert(Tok);
|
2013-01-30 05:01:14 +08:00
|
|
|
CurrentToken = Tok;
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case tok::r_paren:
|
|
|
|
case tok::r_square:
|
|
|
|
return false;
|
|
|
|
case tok::r_brace:
|
2018-04-23 16:50:36 +08:00
|
|
|
// Lines can start with '}'.
|
|
|
|
if (Tok->Previous)
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case tok::greater:
|
2018-04-23 16:50:36 +08:00
|
|
|
if (Style.Language != FormatStyle::LK_TextProto)
|
|
|
|
Tok->Type = TT_BinaryOperator;
|
2013-01-30 05:01:14 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_operator:
|
2018-02-28 03:07:47 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_TextProto ||
|
|
|
|
Style.Language == FormatStyle::LK_Proto)
|
|
|
|
break;
|
2013-09-02 17:20:39 +08:00
|
|
|
while (CurrentToken &&
|
|
|
|
!CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) {
|
2013-03-13 22:41:29 +08:00
|
|
|
if (CurrentToken->isOneOf(tok::star, tok::amp))
|
2013-02-11 16:01:18 +08:00
|
|
|
CurrentToken->Type = TT_PointerOrReference;
|
|
|
|
consumeToken();
|
2016-01-09 23:56:40 +08:00
|
|
|
if (CurrentToken &&
|
2017-11-06 20:11:51 +08:00
|
|
|
CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator,
|
|
|
|
tok::comma))
|
2013-08-28 15:27:35 +08:00
|
|
|
CurrentToken->Previous->Type = TT_OverloadedOperator;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
2013-05-10 15:59:58 +08:00
|
|
|
if (CurrentToken) {
|
2013-02-11 16:01:18 +08:00
|
|
|
CurrentToken->Type = TT_OverloadedOperatorLParen;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (CurrentToken->Previous->is(TT_BinaryOperator))
|
2013-05-29 22:47:47 +08:00
|
|
|
CurrentToken->Previous->Type = TT_OverloadedOperator;
|
2013-05-10 15:59:58 +08:00
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
break;
|
|
|
|
case tok::question:
|
2015-04-13 23:01:40 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next &&
|
2015-06-11 21:29:20 +08:00
|
|
|
Tok->Next->isOneOf(tok::semi, tok::comma, tok::colon, tok::r_paren,
|
2015-04-13 23:01:40 +08:00
|
|
|
tok::r_brace)) {
|
2015-05-05 16:40:32 +08:00
|
|
|
// Question marks before semicolons, colons, etc. indicate optional
|
|
|
|
// types (fields, parameters), e.g.
|
|
|
|
// function(x?: string, y?) {...}
|
|
|
|
// class X { y?; }
|
2015-04-13 23:01:40 +08:00
|
|
|
Tok->Type = TT_JsTypeOptionalQuestion;
|
|
|
|
break;
|
|
|
|
}
|
2015-05-05 16:40:32 +08:00
|
|
|
// Declarations cannot be conditional expressions, this can only be part
|
|
|
|
// of a type declaration.
|
2016-07-12 23:45:53 +08:00
|
|
|
if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
|
2015-05-05 16:40:32 +08:00
|
|
|
Style.Language == FormatStyle::LK_JavaScript)
|
|
|
|
break;
|
2013-01-30 05:01:14 +08:00
|
|
|
parseConditional();
|
|
|
|
break;
|
|
|
|
case tok::kw_template:
|
|
|
|
parseTemplateDeclaration();
|
|
|
|
break;
|
2013-04-03 21:36:17 +08:00
|
|
|
case tok::comma:
|
2015-04-20 20:54:29 +08:00
|
|
|
if (Contexts.back().InCtorInitializer)
|
|
|
|
Tok->Type = TT_CtorInitializerComma;
|
2017-03-10 23:10:37 +08:00
|
|
|
else if (Contexts.back().InInheritanceList)
|
|
|
|
Tok->Type = TT_InheritanceComma;
|
2015-05-19 19:51:39 +08:00
|
|
|
else if (Contexts.back().FirstStartOfName &&
|
2015-06-17 17:43:56 +08:00
|
|
|
(Contexts.size() == 1 || Line.startsWith(tok::kw_for))) {
|
2013-04-03 21:36:17 +08:00
|
|
|
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
|
2015-03-02 02:55:26 +08:00
|
|
|
Line.IsMultiVariableDeclStmt = true;
|
|
|
|
}
|
2014-04-01 20:55:11 +08:00
|
|
|
if (Contexts.back().IsForEachMacro)
|
|
|
|
Contexts.back().IsExpression = true;
|
2013-04-03 21:36:17 +08:00
|
|
|
break;
|
2017-02-11 03:36:52 +08:00
|
|
|
case tok::identifier:
|
|
|
|
if (Tok->isOneOf(Keywords.kw___has_include,
|
|
|
|
Keywords.kw___has_include_next)) {
|
|
|
|
parseHasInclude();
|
|
|
|
}
|
|
|
|
break;
|
2013-01-30 05:01:14 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void parseIncludeDirective() {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (CurrentToken && CurrentToken->is(tok::less)) {
|
2017-09-20 17:51:03 +08:00
|
|
|
next();
|
|
|
|
while (CurrentToken) {
|
2017-05-19 18:34:57 +08:00
|
|
|
// Mark tokens up to the trailing line comments as implicit string
|
|
|
|
// literals.
|
|
|
|
if (CurrentToken->isNot(tok::comment) &&
|
|
|
|
!CurrentToken->TokenText.startswith("//"))
|
2013-01-30 05:01:14 +08:00
|
|
|
CurrentToken->Type = TT_ImplicitStringLiteral;
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void parseWarningOrError() {
|
|
|
|
next();
|
|
|
|
// We still want to format the whitespace left of the first token of the
|
|
|
|
// warning or error.
|
|
|
|
next();
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-01-30 05:01:14 +08:00
|
|
|
CurrentToken->Type = TT_ImplicitStringLiteral;
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-09 21:56:49 +08:00
|
|
|
void parsePragma() {
|
|
|
|
next(); // Consume "pragma".
|
2015-04-22 17:45:42 +08:00
|
|
|
if (CurrentToken &&
|
|
|
|
CurrentToken->isOneOf(Keywords.kw_mark, Keywords.kw_option)) {
|
|
|
|
bool IsMark = CurrentToken->is(Keywords.kw_mark);
|
2014-01-09 21:56:49 +08:00
|
|
|
next(); // Consume "mark".
|
|
|
|
next(); // Consume first token (so we fix leading whitespace).
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2015-04-22 17:45:42 +08:00
|
|
|
if (IsMark || CurrentToken->Previous->is(TT_BinaryOperator))
|
|
|
|
CurrentToken->Type = TT_ImplicitStringLiteral;
|
2014-01-09 21:56:49 +08:00
|
|
|
next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-11 03:36:52 +08:00
|
|
|
void parseHasInclude() {
|
|
|
|
if (!CurrentToken || !CurrentToken->is(tok::l_paren))
|
|
|
|
return;
|
2017-09-20 17:51:03 +08:00
|
|
|
next(); // '('
|
2017-02-11 03:36:52 +08:00
|
|
|
parseIncludeDirective();
|
2017-09-20 17:51:03 +08:00
|
|
|
next(); // ')'
|
2017-02-11 03:36:52 +08:00
|
|
|
}
|
|
|
|
|
2014-11-24 00:46:28 +08:00
|
|
|
LineType parsePreprocessorDirective() {
|
2016-05-29 22:41:36 +08:00
|
|
|
bool IsFirstToken = CurrentToken->IsFirst;
|
2014-11-24 00:46:28 +08:00
|
|
|
LineType Type = LT_PreprocessorDirective;
|
2013-01-30 05:01:14 +08:00
|
|
|
next();
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!CurrentToken)
|
2014-11-24 00:46:28 +08:00
|
|
|
return Type;
|
2016-05-29 22:41:36 +08:00
|
|
|
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && IsFirstToken) {
|
|
|
|
// JavaScript files can contain shebang lines of the form:
|
|
|
|
// #!/usr/bin/env node
|
|
|
|
// Treat these like C++ #include directives.
|
|
|
|
while (CurrentToken) {
|
|
|
|
// Tokens cannot be comments here.
|
|
|
|
CurrentToken->Type = TT_ImplicitStringLiteral;
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
return LT_ImportStatement;
|
|
|
|
}
|
|
|
|
|
2013-10-12 05:43:05 +08:00
|
|
|
if (CurrentToken->Tok.is(tok::numeric_constant)) {
|
|
|
|
CurrentToken->SpacesRequiredBefore = 1;
|
2014-11-24 00:46:28 +08:00
|
|
|
return Type;
|
2013-10-12 05:43:05 +08:00
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
// Hashes in the middle of a line can lead to any strange token
|
|
|
|
// sequence.
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!CurrentToken->Tok.getIdentifierInfo())
|
2014-11-24 00:46:28 +08:00
|
|
|
return Type;
|
2013-05-29 22:47:47 +08:00
|
|
|
switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
|
2013-01-30 05:01:14 +08:00
|
|
|
case tok::pp_include:
|
2015-05-19 19:22:29 +08:00
|
|
|
case tok::pp_include_next:
|
2013-01-30 05:01:14 +08:00
|
|
|
case tok::pp_import:
|
2014-08-13 16:29:18 +08:00
|
|
|
next();
|
2013-01-30 05:01:14 +08:00
|
|
|
parseIncludeDirective();
|
2014-11-24 00:46:28 +08:00
|
|
|
Type = LT_ImportStatement;
|
2013-01-30 05:01:14 +08:00
|
|
|
break;
|
|
|
|
case tok::pp_error:
|
|
|
|
case tok::pp_warning:
|
|
|
|
parseWarningOrError();
|
|
|
|
break;
|
2014-01-09 21:56:49 +08:00
|
|
|
case tok::pp_pragma:
|
|
|
|
parsePragma();
|
|
|
|
break;
|
2013-04-23 21:54:04 +08:00
|
|
|
case tok::pp_if:
|
|
|
|
case tok::pp_elif:
|
2014-01-21 16:56:09 +08:00
|
|
|
Contexts.back().IsExpression = true;
|
2013-04-23 21:54:04 +08:00
|
|
|
parseLine();
|
|
|
|
break;
|
2013-01-30 05:01:14 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-02-11 03:36:52 +08:00
|
|
|
while (CurrentToken) {
|
|
|
|
FormatToken *Tok = CurrentToken;
|
2013-02-05 17:34:14 +08:00
|
|
|
next();
|
2017-04-19 14:06:38 +08:00
|
|
|
if (Tok->is(tok::l_paren))
|
|
|
|
parseParens();
|
|
|
|
else if (Tok->isOneOf(Keywords.kw___has_include,
|
2017-09-20 17:51:03 +08:00
|
|
|
Keywords.kw___has_include_next))
|
2017-02-11 03:36:52 +08:00
|
|
|
parseHasInclude();
|
|
|
|
}
|
2014-11-24 00:46:28 +08:00
|
|
|
return Type;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
Formatter: Correctly format stars in `sizeof(int**)` and similar places.
This redoes how '*' and '&' are classified as pointer / reference markers when
followed by ')', '>', or ','.
Previously, determineStarAmpUsage() marked a single '*' and '&' followed by
')', '>', or ',' as pointer or reference marker. Now, all '*'s and '&'s
preceding ')', '>', or ',' are marked as pointer / reference markers. Fixes
PR14884.
Since only the last '*' in 'int ***' was marked as pointer before (the rest
were unary operators, which don't reach spaceRequiredBetween()),
spaceRequiredBetween() now had to be thought about handing multiple '*'s in
sequence.
Before:
return sizeof(int * *);
Type **A = static_cast<Type * *>(P);
Now:
return sizeof(int**);
Type **A = static_cast<Type **>(P);
While here, also make all methods of AnnotatingParser except parseLine()
private.
Review URL: http://llvm-reviews.chandlerc.com/D384
llvm-svn: 174975
2013-02-13 00:17:07 +08:00
|
|
|
public:
|
2013-01-30 05:01:14 +08:00
|
|
|
LineType parseLine() {
|
2015-05-06 16:38:24 +08:00
|
|
|
NonTemplateLess.clear();
|
2015-04-23 17:54:10 +08:00
|
|
|
if (CurrentToken->is(tok::hash))
|
2014-11-24 00:46:28 +08:00
|
|
|
return parsePreprocessorDirective();
|
2014-01-21 16:56:09 +08:00
|
|
|
|
2014-01-18 00:21:39 +08:00
|
|
|
// Directly allow to 'import <string-literal>' to support protocol buffer
|
2017-11-14 07:27:55 +08:00
|
|
|
// definitions (github.com/google/protobuf) or missing "#" (either way we
|
2014-01-18 00:21:39 +08:00
|
|
|
// should not break the line).
|
|
|
|
IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
|
2014-11-27 02:03:42 +08:00
|
|
|
if ((Style.Language == FormatStyle::LK_Java &&
|
|
|
|
CurrentToken->is(Keywords.kw_package)) ||
|
|
|
|
(Info && Info->getPPKeywordID() == tok::pp_import &&
|
2014-12-04 16:57:27 +08:00
|
|
|
CurrentToken->Next &&
|
2015-01-14 18:02:49 +08:00
|
|
|
CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier,
|
|
|
|
tok::kw_static))) {
|
2014-08-13 16:29:18 +08:00
|
|
|
next();
|
2014-01-18 00:21:39 +08:00
|
|
|
parseIncludeDirective();
|
2014-11-24 00:46:28 +08:00
|
|
|
return LT_ImportStatement;
|
2014-08-13 16:29:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If this line starts and ends in '<' and '>', respectively, it is likely
|
|
|
|
// part of "#define <a/b.h>".
|
|
|
|
if (CurrentToken->is(tok::less) && Line.Last->is(tok::greater)) {
|
|
|
|
parseIncludeDirective();
|
2014-11-24 00:46:28 +08:00
|
|
|
return LT_ImportStatement;
|
2014-08-13 16:29:18 +08:00
|
|
|
}
|
2014-01-18 00:21:39 +08:00
|
|
|
|
2015-04-23 17:54:10 +08:00
|
|
|
// In .proto files, top-level options are very similar to import statements
|
|
|
|
// and should not be line-wrapped.
|
|
|
|
if (Style.Language == FormatStyle::LK_Proto && Line.Level == 0 &&
|
|
|
|
CurrentToken->is(Keywords.kw_option)) {
|
|
|
|
next();
|
|
|
|
if (CurrentToken && CurrentToken->is(tok::identifier))
|
|
|
|
return LT_ImportStatement;
|
|
|
|
}
|
|
|
|
|
2016-06-14 00:39:50 +08:00
|
|
|
bool KeywordVirtualFound = false;
|
|
|
|
bool ImportStatement = false;
|
|
|
|
|
2016-03-22 22:32:20 +08:00
|
|
|
// import {...} from '...';
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
CurrentToken->is(Keywords.kw_import))
|
2016-06-14 00:39:50 +08:00
|
|
|
ImportStatement = true;
|
2016-03-22 22:32:20 +08:00
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
while (CurrentToken) {
|
2013-01-30 05:01:14 +08:00
|
|
|
if (CurrentToken->is(tok::kw_virtual))
|
|
|
|
KeywordVirtualFound = true;
|
2016-03-22 22:32:20 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
// export {...} from '...';
|
|
|
|
// An export followed by "from 'some string';" is a re-export from
|
|
|
|
// another module identified by a URI and is treated as a
|
|
|
|
// LT_ImportStatement (i.e. prevent wraps on it for long URIs).
|
|
|
|
// Just "export {...};" or "export class ..." should not be treated as
|
|
|
|
// an import in this sense.
|
|
|
|
if (Line.First->is(tok::kw_export) &&
|
|
|
|
CurrentToken->is(Keywords.kw_from) && CurrentToken->Next &&
|
|
|
|
CurrentToken->Next->isStringLiteral())
|
|
|
|
ImportStatement = true;
|
|
|
|
if (isClosureImportStatement(*CurrentToken))
|
|
|
|
ImportStatement = true;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
if (!consumeToken())
|
|
|
|
return LT_Invalid;
|
|
|
|
}
|
|
|
|
if (KeywordVirtualFound)
|
|
|
|
return LT_VirtualFunctionDecl;
|
2014-11-24 00:46:28 +08:00
|
|
|
if (ImportStatement)
|
|
|
|
return LT_ImportStatement;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2015-06-17 17:43:56 +08:00
|
|
|
if (Line.startsWith(TT_ObjCMethodSpecifier)) {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (Contexts.back().FirstObjCSelectorName)
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
|
|
|
|
Contexts.back().LongestObjCSelectorName;
|
2013-02-05 18:07:47 +08:00
|
|
|
return LT_ObjCMethodDecl;
|
|
|
|
}
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
return LT_Other;
|
|
|
|
}
|
|
|
|
|
Formatter: Correctly format stars in `sizeof(int**)` and similar places.
This redoes how '*' and '&' are classified as pointer / reference markers when
followed by ')', '>', or ','.
Previously, determineStarAmpUsage() marked a single '*' and '&' followed by
')', '>', or ',' as pointer or reference marker. Now, all '*'s and '&'s
preceding ')', '>', or ',' are marked as pointer / reference markers. Fixes
PR14884.
Since only the last '*' in 'int ***' was marked as pointer before (the rest
were unary operators, which don't reach spaceRequiredBetween()),
spaceRequiredBetween() now had to be thought about handing multiple '*'s in
sequence.
Before:
return sizeof(int * *);
Type **A = static_cast<Type * *>(P);
Now:
return sizeof(int**);
Type **A = static_cast<Type **>(P);
While here, also make all methods of AnnotatingParser except parseLine()
private.
Review URL: http://llvm-reviews.chandlerc.com/D384
llvm-svn: 174975
2013-02-13 00:17:07 +08:00
|
|
|
private:
|
2016-03-22 22:32:20 +08:00
|
|
|
bool isClosureImportStatement(const FormatToken &Tok) {
|
2014-11-24 00:46:28 +08:00
|
|
|
// FIXME: Closure-library specific stuff should not be hard-coded but be
|
|
|
|
// configurable.
|
2016-03-22 22:32:20 +08:00
|
|
|
return Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) &&
|
2017-09-20 17:51:03 +08:00
|
|
|
Tok.Next->Next &&
|
|
|
|
(Tok.Next->Next->TokenText == "module" ||
|
|
|
|
Tok.Next->Next->TokenText == "provide" ||
|
|
|
|
Tok.Next->Next->TokenText == "require" ||
|
|
|
|
Tok.Next->Next->TokenText == "forwardDeclare") &&
|
2014-11-27 22:46:03 +08:00
|
|
|
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
|
2014-11-24 00:46:28 +08:00
|
|
|
}
|
|
|
|
|
2014-03-18 19:22:45 +08:00
|
|
|
void resetTokenMetadata(FormatToken *Token) {
|
2014-05-09 21:11:16 +08:00
|
|
|
if (!Token)
|
|
|
|
return;
|
2014-03-18 19:22:45 +08:00
|
|
|
|
|
|
|
// Reset token type in case we have already looked at it and then
|
|
|
|
// recovered from an error (e.g. failure to find the matching >).
|
2015-05-04 17:22:29 +08:00
|
|
|
if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_ForEachMacro,
|
|
|
|
TT_FunctionLBrace, TT_ImplicitStringLiteral,
|
2015-06-05 21:18:09 +08:00
|
|
|
TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow,
|
2016-11-01 14:22:59 +08:00
|
|
|
TT_OverloadedOperator, TT_RegexLiteral,
|
2017-04-11 17:55:00 +08:00
|
|
|
TT_TemplateString, TT_ObjCStringLiteral))
|
2014-03-18 19:22:45 +08:00
|
|
|
CurrentToken->Type = TT_Unknown;
|
2014-07-19 09:06:45 +08:00
|
|
|
CurrentToken->Role.reset();
|
2015-01-22 02:04:02 +08:00
|
|
|
CurrentToken->MatchingParen = nullptr;
|
2014-03-18 19:22:45 +08:00
|
|
|
CurrentToken->FakeLParens.clear();
|
|
|
|
CurrentToken->FakeRParens = 0;
|
|
|
|
}
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
void next() {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (CurrentToken) {
|
clang-format: Be more conservative about braced list column layout.
Specifically disable it for nested braced lists as it commonly can look
really weird. Eventually, we'll want to become smarter and format some of
the nested lists better.
Before:
SomeStruct my_struct_array = {
{ aaaaaa, aaaaaaaa, aaaaaaaaaa, aaaaaaaaa, aaaaaaaaa,
aaaaaaaaaa, aaaaaaaaaa, aaaaaaa, aaa },
{ aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaa },
{ aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaa, a, aaaaaaaaaa,
aaaaaaaaa, aaa },
};
After:
SomeStruct my_struct_array = {
{ aaaaaa, aaaaaaaa, aaaaaaaaaa, aaaaaaaaa, aaaaaaaaa, aaaaaaaaaa,
aaaaaaaaaaaa, aaaaaaa, aaa },
{ aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaa },
{ aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaa, a, aaaaaaaaaa, aaaaaaaaa, aaa },
};
llvm-svn: 196783
2013-12-09 22:40:19 +08:00
|
|
|
CurrentToken->NestingLevel = Contexts.size() - 1;
|
2014-08-14 18:52:56 +08:00
|
|
|
CurrentToken->BindingStrength = Contexts.back().BindingStrength;
|
2014-11-25 18:05:17 +08:00
|
|
|
modifyContext(*CurrentToken);
|
2014-08-14 18:52:56 +08:00
|
|
|
determineTokenType(*CurrentToken);
|
2013-05-29 22:47:47 +08:00
|
|
|
CurrentToken = CurrentToken->Next;
|
2014-05-08 15:01:45 +08:00
|
|
|
}
|
2013-02-18 20:44:35 +08:00
|
|
|
|
2014-03-18 19:22:45 +08:00
|
|
|
resetTokenMetadata(CurrentToken);
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// A struct to hold information valid in a specific context, e.g.
|
2013-02-06 18:05:46 +08:00
|
|
|
/// a pair of parenthesis.
|
|
|
|
struct Context {
|
2013-03-14 21:45:21 +08:00
|
|
|
Context(tok::TokenKind ContextKind, unsigned BindingStrength,
|
|
|
|
bool IsExpression)
|
|
|
|
: ContextKind(ContextKind), BindingStrength(BindingStrength),
|
2015-04-15 15:26:18 +08:00
|
|
|
IsExpression(IsExpression) {}
|
2013-03-14 21:45:21 +08:00
|
|
|
|
|
|
|
tok::TokenKind ContextKind;
|
2013-02-06 18:05:46 +08:00
|
|
|
unsigned BindingStrength;
|
|
|
|
bool IsExpression;
|
2015-04-15 15:26:18 +08:00
|
|
|
unsigned LongestObjCSelectorName = 0;
|
|
|
|
bool ColonIsForRangeExpr = false;
|
|
|
|
bool ColonIsDictLiteral = false;
|
|
|
|
bool ColonIsObjCMethodExpr = false;
|
|
|
|
FormatToken *FirstObjCSelectorName = nullptr;
|
|
|
|
FormatToken *FirstStartOfName = nullptr;
|
|
|
|
bool CanBeExpression = true;
|
|
|
|
bool InTemplateArgument = false;
|
|
|
|
bool InCtorInitializer = false;
|
2017-03-10 23:10:37 +08:00
|
|
|
bool InInheritanceList = false;
|
2015-04-15 15:26:18 +08:00
|
|
|
bool CaretFound = false;
|
|
|
|
bool IsForEachMacro = false;
|
2018-03-12 23:42:38 +08:00
|
|
|
bool InCpp11AttributeSpecifier = false;
|
2013-02-06 18:05:46 +08:00
|
|
|
};
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Puts a new \c Context onto the stack \c Contexts for the lifetime
|
2013-02-06 18:05:46 +08:00
|
|
|
/// of each instance.
|
|
|
|
struct ScopedContextCreator {
|
|
|
|
AnnotatingParser &P;
|
|
|
|
|
2013-03-14 21:45:21 +08:00
|
|
|
ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind,
|
|
|
|
unsigned Increase)
|
|
|
|
: P(P) {
|
2013-07-08 22:34:09 +08:00
|
|
|
P.Contexts.push_back(Context(ContextKind,
|
|
|
|
P.Contexts.back().BindingStrength + Increase,
|
|
|
|
P.Contexts.back().IsExpression));
|
2013-02-06 18:05:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~ScopedContextCreator() { P.Contexts.pop_back(); }
|
|
|
|
};
|
2013-02-04 15:21:18 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
void modifyContext(const FormatToken &Current) {
|
2013-05-29 22:47:47 +08:00
|
|
|
if (Current.getPrecedence() == prec::Assignment &&
|
2015-12-24 02:01:29 +08:00
|
|
|
!Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) &&
|
2017-06-07 20:53:22 +08:00
|
|
|
// Type aliases use `type X = ...;` in TypeScript and can be exported
|
|
|
|
// using `export type ...`.
|
2016-06-24 03:52:32 +08:00
|
|
|
!(Style.Language == FormatStyle::LK_JavaScript &&
|
2017-06-07 20:53:22 +08:00
|
|
|
(Line.startsWith(Keywords.kw_type, tok::identifier) ||
|
|
|
|
Line.startsWith(tok::kw_export, Keywords.kw_type,
|
|
|
|
tok::identifier))) &&
|
2013-05-29 22:47:47 +08:00
|
|
|
(!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().IsExpression = true;
|
2015-06-17 17:43:56 +08:00
|
|
|
if (!Line.startsWith(TT_UnaryOperator)) {
|
2015-01-24 03:04:49 +08:00
|
|
|
for (FormatToken *Previous = Current.Previous;
|
2015-07-22 06:51:00 +08:00
|
|
|
Previous && Previous->Previous &&
|
|
|
|
!Previous->Previous->isOneOf(tok::comma, tok::semi);
|
2015-01-24 03:04:49 +08:00
|
|
|
Previous = Previous->Previous) {
|
|
|
|
if (Previous->isOneOf(tok::r_square, tok::r_paren)) {
|
|
|
|
Previous = Previous->MatchingParen;
|
|
|
|
if (!Previous)
|
|
|
|
break;
|
|
|
|
}
|
2015-03-11 20:59:49 +08:00
|
|
|
if (Previous->opensScope())
|
|
|
|
break;
|
2015-01-24 03:04:49 +08:00
|
|
|
if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) &&
|
2015-02-25 18:30:06 +08:00
|
|
|
Previous->isOneOf(tok::star, tok::amp, tok::ampamp) &&
|
|
|
|
Previous->Previous && Previous->Previous->isNot(tok::equal))
|
2015-01-24 03:04:49 +08:00
|
|
|
Previous->Type = TT_PointerOrReference;
|
2014-08-13 22:00:41 +08:00
|
|
|
}
|
2013-02-04 15:21:18 +08:00
|
|
|
}
|
2015-05-19 20:29:27 +08:00
|
|
|
} else if (Current.is(tok::lessless) &&
|
|
|
|
(!Current.Previous || !Current.Previous->is(tok::kw_operator))) {
|
|
|
|
Contexts.back().IsExpression = true;
|
2013-12-16 16:36:18 +08:00
|
|
|
} else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
|
2013-02-06 18:05:46 +08:00
|
|
|
Contexts.back().IsExpression = true;
|
2014-11-21 22:08:38 +08:00
|
|
|
} else if (Current.is(TT_TrailingReturnArrow)) {
|
|
|
|
Contexts.back().IsExpression = false;
|
2015-09-16 07:48:17 +08:00
|
|
|
} else if (Current.is(TT_LambdaArrow) || Current.is(Keywords.kw_assert)) {
|
2015-06-05 21:18:09 +08:00
|
|
|
Contexts.back().IsExpression = Style.Language == FormatStyle::LK_Java;
|
2016-05-18 16:02:56 +08:00
|
|
|
} else if (Current.Previous &&
|
|
|
|
Current.Previous->is(TT_CtorInitializerColon)) {
|
|
|
|
Contexts.back().IsExpression = true;
|
|
|
|
Contexts.back().InCtorInitializer = true;
|
2017-09-20 17:51:03 +08:00
|
|
|
} else if (Current.Previous && Current.Previous->is(TT_InheritanceColon)) {
|
2017-03-10 23:10:37 +08:00
|
|
|
Contexts.back().InInheritanceList = true;
|
2013-03-13 22:41:29 +08:00
|
|
|
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
|
2013-05-29 22:47:47 +08:00
|
|
|
for (FormatToken *Previous = Current.Previous;
|
2013-03-13 22:41:29 +08:00
|
|
|
Previous && Previous->isOneOf(tok::star, tok::amp);
|
2013-05-29 22:47:47 +08:00
|
|
|
Previous = Previous->Previous)
|
Formatter: Correctly format stars in `sizeof(int**)` and similar places.
This redoes how '*' and '&' are classified as pointer / reference markers when
followed by ')', '>', or ','.
Previously, determineStarAmpUsage() marked a single '*' and '&' followed by
')', '>', or ',' as pointer or reference marker. Now, all '*'s and '&'s
preceding ')', '>', or ',' are marked as pointer / reference markers. Fixes
PR14884.
Since only the last '*' in 'int ***' was marked as pointer before (the rest
were unary operators, which don't reach spaceRequiredBetween()),
spaceRequiredBetween() now had to be thought about handing multiple '*'s in
sequence.
Before:
return sizeof(int * *);
Type **A = static_cast<Type * *>(P);
Now:
return sizeof(int**);
Type **A = static_cast<Type **>(P);
While here, also make all methods of AnnotatingParser except parseLine()
private.
Review URL: http://llvm-reviews.chandlerc.com/D384
llvm-svn: 174975
2013-02-13 00:17:07 +08:00
|
|
|
Previous->Type = TT_PointerOrReference;
|
2016-02-01 19:21:07 +08:00
|
|
|
if (Line.MustBeDeclaration && !Contexts.front().InCtorInitializer)
|
|
|
|
Contexts.back().IsExpression = false;
|
2013-03-13 15:49:51 +08:00
|
|
|
} else if (Current.is(tok::kw_new)) {
|
|
|
|
Contexts.back().CanBeExpression = false;
|
2015-06-18 18:59:26 +08:00
|
|
|
} else if (Current.isOneOf(tok::semi, tok::exclaim)) {
|
2013-05-03 22:41:24 +08:00
|
|
|
// This should be the condition or increment in a for-loop.
|
|
|
|
Contexts.back().IsExpression = true;
|
Formatter: Correctly format stars in `sizeof(int**)` and similar places.
This redoes how '*' and '&' are classified as pointer / reference markers when
followed by ')', '>', or ','.
Previously, determineStarAmpUsage() marked a single '*' and '&' followed by
')', '>', or ',' as pointer or reference marker. Now, all '*'s and '&'s
preceding ')', '>', or ',' are marked as pointer / reference markers. Fixes
PR14884.
Since only the last '*' in 'int ***' was marked as pointer before (the rest
were unary operators, which don't reach spaceRequiredBetween()),
spaceRequiredBetween() now had to be thought about handing multiple '*'s in
sequence.
Before:
return sizeof(int * *);
Type **A = static_cast<Type * *>(P);
Now:
return sizeof(int**);
Type **A = static_cast<Type **>(P);
While here, also make all methods of AnnotatingParser except parseLine()
private.
Review URL: http://llvm-reviews.chandlerc.com/D384
llvm-svn: 174975
2013-02-13 00:17:07 +08:00
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
}
|
2013-02-04 15:21:18 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
void determineTokenType(FormatToken &Current) {
|
|
|
|
if (!Current.is(TT_Unknown))
|
|
|
|
// The token type is already known.
|
|
|
|
return;
|
|
|
|
|
2017-03-13 17:14:23 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
if (Current.is(tok::exclaim)) {
|
|
|
|
if (Current.Previous &&
|
2017-05-15 16:15:53 +08:00
|
|
|
(Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
|
|
|
|
tok::r_paren, tok::r_square,
|
|
|
|
tok::r_brace) ||
|
2017-03-13 17:14:23 +08:00
|
|
|
Current.Previous->Tok.isLiteral())) {
|
|
|
|
Current.Type = TT_JsNonNullAssertion;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Current.Next &&
|
|
|
|
Current.Next->isOneOf(TT_BinaryOperator, Keywords.kw_as)) {
|
|
|
|
Current.Type = TT_JsNonNullAssertion;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
// Line.MightBeFunctionDecl can only be true after the parentheses of a
|
|
|
|
// function declaration have been found. In this case, 'Current' is a
|
|
|
|
// trailing token of this declaration and thus cannot be a name.
|
|
|
|
if (Current.is(Keywords.kw_instanceof)) {
|
|
|
|
Current.Type = TT_BinaryOperator;
|
|
|
|
} else if (isStartOfName(Current) &&
|
|
|
|
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
|
|
|
|
Contexts.back().FirstStartOfName = &Current;
|
|
|
|
Current.Type = TT_StartOfName;
|
2017-09-03 16:56:24 +08:00
|
|
|
} else if (Current.is(tok::semi)) {
|
|
|
|
// Reset FirstStartOfName after finding a semicolon so that a for loop
|
|
|
|
// with multiple increment statements is not confused with a for loop
|
|
|
|
// having multiple variable declarations.
|
|
|
|
Contexts.back().FirstStartOfName = nullptr;
|
2015-11-11 10:02:15 +08:00
|
|
|
} else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) {
|
2014-11-25 18:05:17 +08:00
|
|
|
AutoFound = true;
|
|
|
|
} else if (Current.is(tok::arrow) &&
|
|
|
|
Style.Language == FormatStyle::LK_Java) {
|
|
|
|
Current.Type = TT_LambdaArrow;
|
|
|
|
} else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration &&
|
|
|
|
Current.NestingLevel == 0) {
|
|
|
|
Current.Type = TT_TrailingReturnArrow;
|
|
|
|
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
|
2017-09-20 17:51:03 +08:00
|
|
|
Current.Type = determineStarAmpUsage(Current,
|
|
|
|
Contexts.back().CanBeExpression &&
|
|
|
|
Contexts.back().IsExpression,
|
|
|
|
Contexts.back().InTemplateArgument);
|
2014-11-25 18:05:17 +08:00
|
|
|
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
|
|
|
|
Current.Type = determinePlusMinusCaretUsage(Current);
|
|
|
|
if (Current.is(TT_UnaryOperator) && Current.is(tok::caret))
|
|
|
|
Contexts.back().CaretFound = true;
|
|
|
|
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
|
|
|
|
Current.Type = determineIncrementUsage(Current);
|
|
|
|
} else if (Current.isOneOf(tok::exclaim, tok::tilde)) {
|
|
|
|
Current.Type = TT_UnaryOperator;
|
|
|
|
} else if (Current.is(tok::question)) {
|
2015-05-05 16:40:32 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
2016-06-24 05:51:49 +08:00
|
|
|
Line.MustBeDeclaration && !Contexts.back().IsExpression) {
|
2015-05-05 16:40:32 +08:00
|
|
|
// In JavaScript, `interface X { foo?(): bar; }` is an optional method
|
|
|
|
// on the interface, not a ternary expression.
|
|
|
|
Current.Type = TT_JsTypeOptionalQuestion;
|
|
|
|
} else {
|
|
|
|
Current.Type = TT_ConditionalExpr;
|
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
} else if (Current.isBinaryOperator() &&
|
2018-02-06 19:34:34 +08:00
|
|
|
(!Current.Previous || Current.Previous->isNot(tok::l_square)) &&
|
|
|
|
(!Current.is(tok::greater) &&
|
|
|
|
Style.Language != FormatStyle::LK_TextProto)) {
|
2014-11-25 18:05:17 +08:00
|
|
|
Current.Type = TT_BinaryOperator;
|
|
|
|
} else if (Current.is(tok::comment)) {
|
2015-05-06 16:58:57 +08:00
|
|
|
if (Current.TokenText.startswith("/*")) {
|
|
|
|
if (Current.TokenText.endswith("*/"))
|
|
|
|
Current.Type = TT_BlockComment;
|
|
|
|
else
|
|
|
|
// The lexer has for some reason determined a comment here. But we
|
|
|
|
// cannot really handle it, if it isn't properly terminated.
|
|
|
|
Current.Tok.setKind(tok::unknown);
|
|
|
|
} else {
|
|
|
|
Current.Type = TT_LineComment;
|
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
} else if (Current.is(tok::r_paren)) {
|
|
|
|
if (rParenEndsCast(Current))
|
|
|
|
Current.Type = TT_CastRParen;
|
2015-05-18 21:47:23 +08:00
|
|
|
if (Current.MatchingParen && Current.Next &&
|
|
|
|
!Current.Next->isBinaryOperator() &&
|
2016-04-06 21:58:09 +08:00
|
|
|
!Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace,
|
clang-format: [Java] Fix bug in enum formatting.
Before:
public enum VeryLongEnum {
ENUM_WITH_MANY_PARAMETERS("aaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccc")
,
SECOND_ENUM("a", "b", "c");
private VeryLongEnum(String a, String b, String c) {}
}
After:
public enum VeryLongEnum {
ENUM_WITH_MANY_PARAMETERS("aaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccc") ,
SECOND_ENUM("a", "b", "c");
private VeryLongEnum(String a, String b, String c) {}
}
llvm-svn: 296499
2017-03-01 02:28:15 +08:00
|
|
|
tok::comma, tok::period, tok::arrow,
|
|
|
|
tok::coloncolon))
|
2016-09-27 06:19:08 +08:00
|
|
|
if (FormatToken *AfterParen = Current.MatchingParen->Next) {
|
|
|
|
// Make sure this isn't the return type of an Obj-C block declaration
|
|
|
|
if (AfterParen->Tok.isNot(tok::caret)) {
|
|
|
|
if (FormatToken *BeforeParen = Current.MatchingParen->Previous)
|
|
|
|
if (BeforeParen->is(tok::identifier) &&
|
|
|
|
BeforeParen->TokenText == BeforeParen->TokenText.upper() &&
|
|
|
|
(!BeforeParen->Previous ||
|
|
|
|
BeforeParen->Previous->ClosesTemplateDeclaration))
|
|
|
|
Current.Type = TT_FunctionAnnotationRParen;
|
|
|
|
}
|
|
|
|
}
|
2017-04-26 20:36:49 +08:00
|
|
|
} else if (Current.is(tok::at) && Current.Next &&
|
|
|
|
Style.Language != FormatStyle::LK_JavaScript &&
|
|
|
|
Style.Language != FormatStyle::LK_Java) {
|
|
|
|
// In Java & JavaScript, "@..." is a decorator or annotation. In ObjC, it
|
|
|
|
// marks declarations and properties that need special formatting.
|
2017-04-11 17:55:00 +08:00
|
|
|
switch (Current.Next->Tok.getObjCKeywordID()) {
|
|
|
|
case tok::objc_interface:
|
|
|
|
case tok::objc_implementation:
|
|
|
|
case tok::objc_protocol:
|
|
|
|
Current.Type = TT_ObjCDecl;
|
|
|
|
break;
|
|
|
|
case tok::objc_property:
|
|
|
|
Current.Type = TT_ObjCProperty;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2014-11-24 23:42:34 +08:00
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
} else if (Current.is(tok::period)) {
|
|
|
|
FormatToken *PreviousNoComment = Current.getPreviousNonComment();
|
|
|
|
if (PreviousNoComment &&
|
|
|
|
PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
|
|
|
|
Current.Type = TT_DesignatedInitializerPeriod;
|
2015-01-10 07:25:06 +08:00
|
|
|
else if (Style.Language == FormatStyle::LK_Java && Current.Previous &&
|
|
|
|
Current.Previous->isOneOf(TT_JavaAnnotation,
|
|
|
|
TT_LeadingJavaAnnotation)) {
|
|
|
|
Current.Type = Current.Previous->Type;
|
|
|
|
}
|
2018-04-28 02:51:12 +08:00
|
|
|
} else if (canBeObjCSelectorComponent(Current) &&
|
[clang-format] Ensure ObjC selectors with 0 args are annotated correctly
Summary:
Previously, clang-format would incorrectly annotate 0-argument
Objective-C selector names as TT_TrailingAnnotation:
```
% echo "-(void)foo;" > /tmp/test.m
% ./bin/clang-format -debug /tmp/test.m
Language: Objective-C
----
Line(0, FSC=0): minus[T=68, OC=0] l_paren[T=68, OC=1] void[T=68, OC=2]
r_paren[T=68, OC=6] identifier[T=68, OC=7] semi[T=68, OC=10]
Line(0, FSC=0): eof[T=68, OC=0]
Run 0...
AnnotatedTokens(L=0):
M=0 C=0 T=ObjCMethodSpecifier S=1 B=0 BK=0 P=0 Name=minus L=1 PPK=2
FakeLParens= FakeRParens=0 Text='-'
M=0 C=1 T=Unknown S=1 B=0 BK=0 P=33 Name=l_paren L=3 PPK=2
FakeLParens= FakeRParens=0 Text='('
M=0 C=1 T=Unknown S=0 B=0 BK=0 P=140 Name=void L=7 PPK=2 FakeLParens=
FakeRParens=0 Text='void'
M=0 C=0 T=CastRParen S=0 B=0 BK=0 P=43 Name=r_paren L=8 PPK=2
FakeLParens= FakeRParens=0 Text=')'
M=0 C=1 T=TrailingAnnotation S=0 B=0 BK=0 P=120 Name=identifier L=11
PPK=2 FakeLParens= FakeRParens=0 Text='foo'
M=0 C=0 T=Unknown S=0 B=0 BK=0 P=23 Name=semi L=12 PPK=2 FakeLParens=
FakeRParens=0 Text=';'
```
This caused us to incorrectly indent 0-argument wrapped selectors
when Style.IndentWrappedFunctionNames was false, as we thought
the 0-argument ObjC selector name was actually a trailing
annotation (which is always indented).
This diff fixes the issue and adds tests.
Test Plan: New tests added. Confirmed tests failed before diff.
After diff, tests passed. Ran tests with:
% make -j12 FormatTests &&
./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper, jolesiak
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D44996
llvm-svn: 329297
2018-04-05 23:26:23 +08:00
|
|
|
// FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
|
|
|
|
Current.Previous && Current.Previous->is(TT_CastRParen) &&
|
|
|
|
Current.Previous->MatchingParen &&
|
|
|
|
Current.Previous->MatchingParen->Previous &&
|
|
|
|
Current.Previous->MatchingParen->Previous->is(
|
|
|
|
TT_ObjCMethodSpecifier)) {
|
|
|
|
// This is the first part of an Objective-C selector name. (If there's no
|
|
|
|
// colon after this, this is the only place which annotates the identifier
|
|
|
|
// as a selector.)
|
|
|
|
Current.Type = TT_SelectorName;
|
2014-11-25 18:05:17 +08:00
|
|
|
} else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
|
|
|
|
Current.Previous &&
|
|
|
|
!Current.Previous->isOneOf(tok::equal, tok::at) &&
|
|
|
|
Line.MightBeFunctionDecl && Contexts.size() == 1) {
|
|
|
|
// Line.MightBeFunctionDecl can only be true after the parentheses of a
|
|
|
|
// function declaration have been found.
|
|
|
|
Current.Type = TT_TrailingAnnotation;
|
2015-02-19 01:17:15 +08:00
|
|
|
} else if ((Style.Language == FormatStyle::LK_Java ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript) &&
|
|
|
|
Current.Previous) {
|
2015-01-10 07:25:06 +08:00
|
|
|
if (Current.Previous->is(tok::at) &&
|
|
|
|
Current.isNot(Keywords.kw_interface)) {
|
|
|
|
const FormatToken &AtToken = *Current.Previous;
|
|
|
|
const FormatToken *Previous = AtToken.getPreviousNonComment();
|
|
|
|
if (!Previous || Previous->is(TT_LeadingJavaAnnotation))
|
|
|
|
Current.Type = TT_LeadingJavaAnnotation;
|
|
|
|
else
|
|
|
|
Current.Type = TT_JavaAnnotation;
|
|
|
|
} else if (Current.Previous->is(tok::period) &&
|
|
|
|
Current.Previous->isOneOf(TT_JavaAnnotation,
|
|
|
|
TT_LeadingJavaAnnotation)) {
|
|
|
|
Current.Type = Current.Previous->Type;
|
|
|
|
}
|
2013-02-04 15:21:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Take a guess at whether \p Tok starts a name of a function or
|
2013-07-02 17:47:29 +08:00
|
|
|
/// variable declaration.
|
|
|
|
///
|
|
|
|
/// This is a heuristic based on whether \p Tok is an identifier following
|
|
|
|
/// something that is likely a type.
|
|
|
|
bool isStartOfName(const FormatToken &Tok) {
|
2014-05-09 16:15:10 +08:00
|
|
|
if (Tok.isNot(tok::identifier) || !Tok.Previous)
|
2013-07-02 17:47:29 +08:00
|
|
|
return false;
|
|
|
|
|
2017-03-02 03:26:12 +08:00
|
|
|
if (Tok.Previous->isOneOf(TT_LeadingJavaAnnotation, Keywords.kw_instanceof,
|
|
|
|
Keywords.kw_as))
|
2015-02-19 07:48:37 +08:00
|
|
|
return false;
|
2016-02-01 19:20:47 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
Tok.Previous->is(Keywords.kw_in))
|
|
|
|
return false;
|
2015-01-14 18:00:20 +08:00
|
|
|
|
2013-07-02 17:47:29 +08:00
|
|
|
// Skip "const" as it does not have an influence on whether this is a name.
|
2017-03-07 22:48:02 +08:00
|
|
|
FormatToken *PreviousNotConst = Tok.getPreviousNonComment();
|
2014-05-09 16:15:10 +08:00
|
|
|
while (PreviousNotConst && PreviousNotConst->is(tok::kw_const))
|
2017-03-07 22:48:02 +08:00
|
|
|
PreviousNotConst = PreviousNotConst->getPreviousNonComment();
|
2013-07-02 17:47:29 +08:00
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!PreviousNotConst)
|
2013-07-02 17:47:29 +08:00
|
|
|
return false;
|
|
|
|
|
2013-07-08 22:34:09 +08:00
|
|
|
bool IsPPKeyword = PreviousNotConst->is(tok::identifier) &&
|
|
|
|
PreviousNotConst->Previous &&
|
|
|
|
PreviousNotConst->Previous->is(tok::hash);
|
2013-07-02 17:47:29 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (PreviousNotConst->is(TT_TemplateCloser))
|
2013-08-19 18:16:18 +08:00
|
|
|
return PreviousNotConst && PreviousNotConst->MatchingParen &&
|
|
|
|
PreviousNotConst->MatchingParen->Previous &&
|
2014-11-20 17:48:11 +08:00
|
|
|
PreviousNotConst->MatchingParen->Previous->isNot(tok::period) &&
|
2013-08-19 18:16:18 +08:00
|
|
|
PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template);
|
|
|
|
|
2014-05-05 21:48:09 +08:00
|
|
|
if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen &&
|
|
|
|
PreviousNotConst->MatchingParen->Previous &&
|
|
|
|
PreviousNotConst->MatchingParen->Previous->is(tok::kw_decltype))
|
|
|
|
return true;
|
|
|
|
|
2015-08-25 21:40:51 +08:00
|
|
|
return (!IsPPKeyword &&
|
|
|
|
PreviousNotConst->isOneOf(tok::identifier, tok::kw_auto)) ||
|
2014-11-25 18:05:17 +08:00
|
|
|
PreviousNotConst->is(TT_PointerOrReference) ||
|
2014-01-16 17:11:55 +08:00
|
|
|
PreviousNotConst->isSimpleTypeSpecifier();
|
2013-07-02 17:47:29 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Determine whether ')' is ending a cast.
|
2014-05-06 17:08:34 +08:00
|
|
|
bool rParenEndsCast(const FormatToken &Tok) {
|
2015-11-23 23:55:55 +08:00
|
|
|
// C-style casts are only used in C++ and Java.
|
2017-03-31 21:30:24 +08:00
|
|
|
if (!Style.isCpp() && Style.Language != FormatStyle::LK_Java)
|
2015-11-23 23:55:55 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Empty parens aren't casts and there are no casts at the end of the line.
|
|
|
|
if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
|
|
|
|
return false;
|
2015-11-23 23:55:50 +08:00
|
|
|
|
2015-11-23 23:55:55 +08:00
|
|
|
FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
|
2015-11-23 23:55:50 +08:00
|
|
|
if (LeftOfParens) {
|
2016-06-13 15:49:09 +08:00
|
|
|
// If there is a closing parenthesis left of the current parentheses,
|
2015-11-24 03:11:45 +08:00
|
|
|
// look past it as these might be chained casts.
|
|
|
|
if (LeftOfParens->is(tok::r_paren)) {
|
|
|
|
if (!LeftOfParens->MatchingParen ||
|
|
|
|
!LeftOfParens->MatchingParen->Previous)
|
|
|
|
return false;
|
|
|
|
LeftOfParens = LeftOfParens->MatchingParen->Previous;
|
|
|
|
}
|
|
|
|
|
2015-11-23 23:55:55 +08:00
|
|
|
// If there is an identifier (or with a few exceptions a keyword) right
|
|
|
|
// before the parentheses, this is unlikely to be a cast.
|
2015-11-23 23:55:50 +08:00
|
|
|
if (LeftOfParens->Tok.getIdentifierInfo() &&
|
|
|
|
!LeftOfParens->isOneOf(Keywords.kw_in, tok::kw_return, tok::kw_case,
|
|
|
|
tok::kw_delete))
|
|
|
|
return false;
|
2015-11-23 23:55:55 +08:00
|
|
|
|
|
|
|
// Certain other tokens right before the parentheses are also signals that
|
|
|
|
// this cannot be a cast.
|
|
|
|
if (LeftOfParens->isOneOf(tok::at, tok::r_square, TT_OverloadedOperator,
|
2016-06-13 15:49:09 +08:00
|
|
|
TT_TemplateCloser, tok::ellipsis))
|
2015-11-23 23:55:50 +08:00
|
|
|
return false;
|
2014-11-26 20:23:10 +08:00
|
|
|
}
|
2015-11-23 23:55:55 +08:00
|
|
|
|
|
|
|
if (Tok.Next->is(tok::question))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// As Java has no function types, a "(" after the ")" likely means that this
|
|
|
|
// is a cast.
|
|
|
|
if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// If a (non-string) literal follows, this is likely a cast.
|
|
|
|
if (Tok.Next->isNot(tok::string_literal) &&
|
|
|
|
(Tok.Next->Tok.isLiteral() ||
|
|
|
|
Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Heuristically try to determine whether the parentheses contain a type.
|
2014-11-25 18:05:17 +08:00
|
|
|
bool ParensAreType =
|
|
|
|
!Tok.Previous ||
|
|
|
|
Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) ||
|
|
|
|
Tok.Previous->isSimpleTypeSpecifier();
|
2014-05-06 17:08:34 +08:00
|
|
|
bool ParensCouldEndDecl =
|
2015-10-26 20:08:47 +08:00
|
|
|
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
|
2015-12-28 15:44:25 +08:00
|
|
|
if (ParensAreType && !ParensCouldEndDecl)
|
2015-11-23 23:55:55 +08:00
|
|
|
return true;
|
2014-05-06 17:08:34 +08:00
|
|
|
|
2015-11-23 23:55:55 +08:00
|
|
|
// At this point, we heuristically assume that there are no casts at the
|
|
|
|
// start of the line. We assume that we have found most cases where there
|
|
|
|
// are by the logic above, e.g. "(void)x;".
|
|
|
|
if (!LeftOfParens)
|
|
|
|
return false;
|
|
|
|
|
2016-11-12 15:38:22 +08:00
|
|
|
// Certain token types inside the parentheses mean that this can't be a
|
|
|
|
// cast.
|
|
|
|
for (const FormatToken *Token = Tok.MatchingParen->Next; Token != &Tok;
|
|
|
|
Token = Token->Next)
|
|
|
|
if (Token->is(TT_BinaryOperator))
|
|
|
|
return false;
|
|
|
|
|
2016-04-05 19:46:06 +08:00
|
|
|
// If the following token is an identifier or 'this', this is a cast. All
|
|
|
|
// cases where this can be something else are handled above.
|
|
|
|
if (Tok.Next->isOneOf(tok::identifier, tok::kw_this))
|
2015-11-23 23:55:55 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!Tok.Next->Next)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the next token after the parenthesis is a unary operator, assume
|
|
|
|
// that this is cast, unless there are unexpected tokens inside the
|
|
|
|
// parenthesis.
|
|
|
|
bool NextIsUnary =
|
|
|
|
Tok.Next->isUnaryOperator() || Tok.Next->isOneOf(tok::amp, tok::star);
|
|
|
|
if (!NextIsUnary || Tok.Next->is(tok::plus) ||
|
|
|
|
!Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant))
|
|
|
|
return false;
|
|
|
|
// Search for unexpected tokens.
|
|
|
|
for (FormatToken *Prev = Tok.Previous; Prev != Tok.MatchingParen;
|
|
|
|
Prev = Prev->Previous) {
|
|
|
|
if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon))
|
|
|
|
return false;
|
2014-05-06 17:08:34 +08:00
|
|
|
}
|
2015-11-23 23:55:55 +08:00
|
|
|
return true;
|
2014-05-06 17:08:34 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Return the type of the given token assuming it is * or &.
|
2014-03-27 19:17:36 +08:00
|
|
|
TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression,
|
|
|
|
bool InTemplateArgument) {
|
2014-09-05 16:53:45 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript)
|
|
|
|
return TT_BinaryOperator;
|
|
|
|
|
2013-07-04 22:47:51 +08:00
|
|
|
const FormatToken *PrevToken = Tok.getPreviousNonComment();
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!PrevToken)
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_UnaryOperator;
|
|
|
|
|
2013-07-04 22:47:51 +08:00
|
|
|
const FormatToken *NextToken = Tok.getNextNonComment();
|
2017-03-08 17:49:12 +08:00
|
|
|
if (!NextToken ||
|
|
|
|
NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const) ||
|
2014-11-21 22:08:38 +08:00
|
|
|
(NextToken->is(tok::l_brace) && !NextToken->getNextNonComment()))
|
2015-08-24 22:28:08 +08:00
|
|
|
return TT_PointerOrReference;
|
2013-02-04 15:21:18 +08:00
|
|
|
|
2014-08-29 20:54:38 +08:00
|
|
|
if (PrevToken->is(tok::coloncolon))
|
2013-03-02 01:13:29 +08:00
|
|
|
return TT_PointerOrReference;
|
|
|
|
|
2013-03-13 22:41:29 +08:00
|
|
|
if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
|
2013-03-14 18:50:25 +08:00
|
|
|
tok::comma, tok::semi, tok::kw_return, tok::colon,
|
2017-07-17 23:27:53 +08:00
|
|
|
tok::equal, tok::kw_delete, tok::kw_sizeof,
|
|
|
|
tok::kw_throw) ||
|
2014-11-25 18:05:17 +08:00
|
|
|
PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
|
|
|
|
TT_UnaryOperator, TT_CastRParen))
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_UnaryOperator;
|
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (NextToken->is(tok::l_square) && NextToken->isNot(TT_LambdaLSquare))
|
2013-02-06 14:20:11 +08:00
|
|
|
return TT_PointerOrReference;
|
2015-10-07 09:41:14 +08:00
|
|
|
if (NextToken->is(tok::kw_operator) && !IsExpression)
|
|
|
|
return TT_PointerOrReference;
|
|
|
|
if (NextToken->isOneOf(tok::comma, tok::semi))
|
2014-06-23 15:36:18 +08:00
|
|
|
return TT_PointerOrReference;
|
2013-02-06 14:20:11 +08:00
|
|
|
|
2017-08-14 19:06:07 +08:00
|
|
|
if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen) {
|
|
|
|
FormatToken *TokenBeforeMatchingParen =
|
|
|
|
PrevToken->MatchingParen->getPreviousNonComment();
|
|
|
|
if (TokenBeforeMatchingParen &&
|
|
|
|
TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype))
|
|
|
|
return TT_PointerOrReference;
|
|
|
|
}
|
2013-09-10 18:26:38 +08:00
|
|
|
|
2014-03-28 17:27:09 +08:00
|
|
|
if (PrevToken->Tok.isLiteral() ||
|
|
|
|
PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
|
2014-10-29 02:28:22 +08:00
|
|
|
tok::kw_false, tok::r_brace) ||
|
2014-03-28 17:27:09 +08:00
|
|
|
NextToken->Tok.isLiteral() ||
|
|
|
|
NextToken->isOneOf(tok::kw_true, tok::kw_false) ||
|
|
|
|
NextToken->isUnaryOperator() ||
|
2014-03-27 19:17:36 +08:00
|
|
|
// If we know we're in a template argument, there are no named
|
|
|
|
// declarations. Thus, having an identifier on the right-hand side
|
|
|
|
// indicates a binary operator.
|
|
|
|
(InTemplateArgument && NextToken->Tok.isAnyIdentifier()))
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_BinaryOperator;
|
|
|
|
|
2014-10-29 02:11:52 +08:00
|
|
|
// "&&(" is quite unlikely to be two successive unary "&".
|
|
|
|
if (Tok.is(tok::ampamp) && NextToken && NextToken->is(tok::l_paren))
|
|
|
|
return TT_BinaryOperator;
|
|
|
|
|
2014-06-02 19:54:20 +08:00
|
|
|
// This catches some cases where evaluation order is used as control flow:
|
|
|
|
// aaa && aaa->f();
|
|
|
|
const FormatToken *NextNextToken = NextToken->getNextNonComment();
|
|
|
|
if (NextNextToken && NextNextToken->is(tok::arrow))
|
|
|
|
return TT_BinaryOperator;
|
|
|
|
|
2013-02-04 15:21:18 +08:00
|
|
|
// It is very unlikely that we are going to find a pointer or reference type
|
|
|
|
// definition on the RHS of an assignment.
|
2014-11-24 03:15:35 +08:00
|
|
|
if (IsExpression && !Contexts.back().CaretFound)
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_BinaryOperator;
|
|
|
|
|
|
|
|
return TT_PointerOrReference;
|
|
|
|
}
|
|
|
|
|
2013-05-29 22:47:47 +08:00
|
|
|
TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
|
2013-07-04 22:47:51 +08:00
|
|
|
const FormatToken *PrevToken = Tok.getPreviousNonComment();
|
2016-11-09 22:12:55 +08:00
|
|
|
if (!PrevToken)
|
|
|
|
return TT_UnaryOperator;
|
|
|
|
|
2018-03-06 21:56:28 +08:00
|
|
|
if (PrevToken->isOneOf(TT_CastRParen, TT_UnaryOperator))
|
|
|
|
// This must be a sequence of leading unary operators.
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_UnaryOperator;
|
|
|
|
|
|
|
|
// Use heuristics to recognize unary operators.
|
2013-03-13 22:41:29 +08:00
|
|
|
if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square,
|
|
|
|
tok::question, tok::colon, tok::kw_return,
|
|
|
|
tok::kw_case, tok::at, tok::l_brace))
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_UnaryOperator;
|
|
|
|
|
2013-02-06 00:21:00 +08:00
|
|
|
// There can't be two consecutive binary operators.
|
2014-11-25 18:05:17 +08:00
|
|
|
if (PrevToken->is(TT_BinaryOperator))
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_UnaryOperator;
|
|
|
|
|
|
|
|
// Fall back to marking the token as binary operator.
|
|
|
|
return TT_BinaryOperator;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Determine whether ++/-- are pre- or post-increments/-decrements.
|
2013-05-29 22:47:47 +08:00
|
|
|
TokenType determineIncrementUsage(const FormatToken &Tok) {
|
2013-07-04 22:47:51 +08:00
|
|
|
const FormatToken *PrevToken = Tok.getPreviousNonComment();
|
2014-11-25 18:05:17 +08:00
|
|
|
if (!PrevToken || PrevToken->is(TT_CastRParen))
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_UnaryOperator;
|
2013-03-13 22:41:29 +08:00
|
|
|
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
|
2013-02-04 15:21:18 +08:00
|
|
|
return TT_TrailingUnaryOperator;
|
|
|
|
|
|
|
|
return TT_UnaryOperator;
|
|
|
|
}
|
2013-02-06 18:05:46 +08:00
|
|
|
|
|
|
|
SmallVector<Context, 8> Contexts;
|
|
|
|
|
clang-format: Add column layout formatting for braced lists
With this patch, braced lists (with more than 3 elements are formatted in a
column layout if possible). E.g.:
static const uint16_t CallerSavedRegs64Bit[] = {
X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,
X86::R8, X86::R9, X86::R10, X86::R11, 0
};
Required other changes:
- FormatTokens can now have a special role that contains extra data and can do
special formattings. A comma separated list is currently the only
implementation.
- Move penalty calculation entirely into ContinuationIndenter (there was a last
piece still in UnwrappedLineFormatter).
Review: http://llvm-reviews.chandlerc.com/D1457
llvm-svn: 189018
2013-08-22 23:00:41 +08:00
|
|
|
const FormatStyle &Style;
|
2013-02-06 18:05:46 +08:00
|
|
|
AnnotatedLine &Line;
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *CurrentToken;
|
2013-07-09 22:36:48 +08:00
|
|
|
bool AutoFound;
|
2014-11-04 20:41:02 +08:00
|
|
|
const AdditionalKeywords &Keywords;
|
2015-05-06 16:38:24 +08:00
|
|
|
|
|
|
|
// Set of "<" tokens that do not open a template parameter list. If parseAngle
|
|
|
|
// determines that a specific token can't be a template opener, it will make
|
|
|
|
// same decision irrespective of the decisions for tokens leading up to it.
|
|
|
|
// Store this information to prevent this from causing exponential runtime.
|
|
|
|
llvm::SmallPtrSet<FormatToken *, 16> NonTemplateLess;
|
2013-01-30 05:01:14 +08:00
|
|
|
};
|
|
|
|
|
2015-03-09 00:06:46 +08:00
|
|
|
static const int PrecedenceUnaryOperator = prec::PointerToMember + 1;
|
|
|
|
static const int PrecedenceArrowAndPeriod = prec::PointerToMember + 2;
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parses binary expressions by inserting fake parenthesis based on
|
2013-02-08 23:28:42 +08:00
|
|
|
/// operator precedence.
|
|
|
|
class ExpressionParser {
|
|
|
|
public:
|
2014-11-04 20:41:02 +08:00
|
|
|
ExpressionParser(const FormatStyle &Style, const AdditionalKeywords &Keywords,
|
|
|
|
AnnotatedLine &Line)
|
|
|
|
: Style(Style), Keywords(Keywords), Current(Line.First) {}
|
2013-02-08 23:28:42 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse expressions with the given operator precedence.
|
2013-02-24 05:01:55 +08:00
|
|
|
void parse(int Precedence = 0) {
|
clang-format: Improve ObjC variadic and binary expression parameters.
Before:
[self aaaaaaaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];
[self aaaaaaaaaaaaaaa:aaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];
After:
[self aaaaaaaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];
[self aaaaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];
This addresses llvm.org/PR15349 and llvm.org/PR16185.
llvm-svn: 194214
2013-11-08 03:23:49 +08:00
|
|
|
// Skip 'return' and ObjC selector colons as they are not part of a binary
|
|
|
|
// expression.
|
2014-11-25 18:05:17 +08:00
|
|
|
while (Current && (Current->is(tok::kw_return) ||
|
|
|
|
(Current->is(tok::colon) &&
|
|
|
|
Current->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))))
|
2013-09-30 16:29:03 +08:00
|
|
|
next();
|
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!Current || Precedence > PrecedenceArrowAndPeriod)
|
2013-08-23 23:14:03 +08:00
|
|
|
return;
|
|
|
|
|
2013-05-31 22:56:12 +08:00
|
|
|
// Conditional expressions need to be parsed separately for proper nesting.
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
if (Precedence == prec::Conditional) {
|
2013-05-31 22:56:12 +08:00
|
|
|
parseConditionalExpr();
|
|
|
|
return;
|
|
|
|
}
|
2013-08-23 23:14:03 +08:00
|
|
|
|
|
|
|
// Parse unary operators, which all have a higher precedence than binary
|
|
|
|
// operators.
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
if (Precedence == PrecedenceUnaryOperator) {
|
2013-08-23 23:14:03 +08:00
|
|
|
parseUnaryOperator();
|
2013-02-08 23:28:42 +08:00
|
|
|
return;
|
2013-08-23 23:14:03 +08:00
|
|
|
}
|
2013-02-08 23:28:42 +08:00
|
|
|
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Start = Current;
|
2014-05-09 16:15:10 +08:00
|
|
|
FormatToken *LatestOperator = nullptr;
|
2014-04-16 20:26:54 +08:00
|
|
|
unsigned OperatorIndex = 0;
|
2013-02-08 23:28:42 +08:00
|
|
|
|
2013-02-24 05:01:55 +08:00
|
|
|
while (Current) {
|
2013-02-08 23:28:42 +08:00
|
|
|
// Consume operators with higher precedence.
|
2013-04-09 04:33:42 +08:00
|
|
|
parse(Precedence + 1);
|
2013-02-08 23:28:42 +08:00
|
|
|
|
2013-08-23 23:14:03 +08:00
|
|
|
int CurrentPrecedence = getCurrentPrecedence();
|
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Current && Current->is(TT_SelectorName) &&
|
2013-12-23 15:29:06 +08:00
|
|
|
Precedence == CurrentPrecedence) {
|
|
|
|
if (LatestOperator)
|
|
|
|
addFakeParenthesis(Start, prec::Level(Precedence));
|
2013-08-23 23:14:03 +08:00
|
|
|
Start = Current;
|
2013-12-23 15:29:06 +08:00
|
|
|
}
|
2013-02-24 05:01:55 +08:00
|
|
|
|
2013-02-08 23:28:42 +08:00
|
|
|
// At the end of the line or when an operator with higher precedence is
|
|
|
|
// found, insert fake parenthesis and return.
|
2017-02-03 22:32:38 +08:00
|
|
|
if (!Current ||
|
|
|
|
(Current->closesScope() &&
|
|
|
|
(Current->MatchingParen || Current->is(TT_TemplateString))) ||
|
2014-11-14 21:03:40 +08:00
|
|
|
(CurrentPrecedence != -1 && CurrentPrecedence < Precedence) ||
|
|
|
|
(CurrentPrecedence == prec::Conditional &&
|
|
|
|
Precedence == prec::Assignment && Current->is(tok::colon))) {
|
2014-12-03 21:20:49 +08:00
|
|
|
break;
|
2013-02-08 23:28:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Consume scopes: (), [], <> and {}
|
2013-04-10 17:49:49 +08:00
|
|
|
if (Current->opensScope()) {
|
2017-01-31 21:03:07 +08:00
|
|
|
// In fragment of a JavaScript template string can look like '}..${' and
|
|
|
|
// thus close a scope and open a new one at the same time.
|
|
|
|
while (Current && (!Current->closesScope() || Current->opensScope())) {
|
2013-02-08 23:28:42 +08:00
|
|
|
next();
|
|
|
|
parse();
|
|
|
|
}
|
|
|
|
next();
|
|
|
|
} else {
|
|
|
|
// Operator found.
|
2014-04-16 20:26:54 +08:00
|
|
|
if (CurrentPrecedence == Precedence) {
|
2016-01-05 21:03:50 +08:00
|
|
|
if (LatestOperator)
|
|
|
|
LatestOperator->NextOperator = Current;
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
LatestOperator = Current;
|
2014-04-16 20:26:54 +08:00
|
|
|
Current->OperatorIndex = OperatorIndex;
|
|
|
|
++OperatorIndex;
|
|
|
|
}
|
2014-11-12 07:04:51 +08:00
|
|
|
next(/*SkipPastLeadingComments=*/Precedence > 0);
|
2013-02-08 23:28:42 +08:00
|
|
|
}
|
|
|
|
}
|
2014-12-03 21:20:49 +08:00
|
|
|
|
|
|
|
if (LatestOperator && (Current || Precedence > 0)) {
|
2016-01-05 21:03:50 +08:00
|
|
|
// LatestOperator->LastOperator = true;
|
2014-12-03 21:20:49 +08:00
|
|
|
if (Precedence == PrecedenceArrowAndPeriod) {
|
|
|
|
// Call expressions don't have a binary operator precedence.
|
|
|
|
addFakeParenthesis(Start, prec::Unknown);
|
|
|
|
} else {
|
|
|
|
addFakeParenthesis(Start, prec::Level(Precedence));
|
|
|
|
}
|
|
|
|
}
|
2013-02-08 23:28:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Gets the precedence (+1) of the given token for binary operators
|
2013-08-23 23:14:03 +08:00
|
|
|
/// and other tokens that we treat like binary operators.
|
|
|
|
int getCurrentPrecedence() {
|
|
|
|
if (Current) {
|
2014-09-05 16:29:31 +08:00
|
|
|
const FormatToken *NextNonComment = Current->getNextNonComment();
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Current->is(TT_ConditionalExpr))
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
return prec::Conditional;
|
2017-06-29 21:30:41 +08:00
|
|
|
if (NextNonComment && Current->is(TT_SelectorName) &&
|
2017-08-15 00:09:08 +08:00
|
|
|
(NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) ||
|
2017-07-03 23:05:14 +08:00
|
|
|
((Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) &&
|
2017-06-29 21:30:41 +08:00
|
|
|
NextNonComment->is(tok::less))))
|
2017-03-02 03:47:28 +08:00
|
|
|
return prec::Assignment;
|
|
|
|
if (Current->is(TT_JsComputedPropertyName))
|
|
|
|
return prec::Assignment;
|
2015-06-04 01:08:40 +08:00
|
|
|
if (Current->is(TT_LambdaArrow))
|
2014-11-21 20:14:12 +08:00
|
|
|
return prec::Comma;
|
2015-06-04 01:08:40 +08:00
|
|
|
if (Current->is(TT_JsFatArrow))
|
2015-06-05 16:25:37 +08:00
|
|
|
return prec::Assignment;
|
2017-03-02 03:47:28 +08:00
|
|
|
if (Current->isOneOf(tok::semi, TT_InlineASMColon, TT_SelectorName) ||
|
2015-06-04 01:08:40 +08:00
|
|
|
(Current->is(tok::comment) && NextNonComment &&
|
|
|
|
NextNonComment->is(TT_SelectorName)))
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
return 0;
|
2015-06-04 01:08:40 +08:00
|
|
|
if (Current->is(TT_RangeBasedForLoopColon))
|
2014-02-07 18:09:46 +08:00
|
|
|
return prec::Comma;
|
2015-07-03 18:12:53 +08:00
|
|
|
if ((Style.Language == FormatStyle::LK_Java ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript) &&
|
|
|
|
Current->is(Keywords.kw_instanceof))
|
|
|
|
return prec::Relational;
|
2016-02-01 19:20:47 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
2017-03-02 03:26:12 +08:00
|
|
|
Current->isOneOf(Keywords.kw_in, Keywords.kw_as))
|
2016-02-01 19:20:47 +08:00
|
|
|
return prec::Relational;
|
2015-06-04 01:08:40 +08:00
|
|
|
if (Current->is(TT_BinaryOperator) || Current->is(tok::comma))
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
return Current->getPrecedence();
|
2015-06-04 01:08:40 +08:00
|
|
|
if (Current->isOneOf(tok::period, tok::arrow))
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
return PrecedenceArrowAndPeriod;
|
2016-06-14 19:28:02 +08:00
|
|
|
if ((Style.Language == FormatStyle::LK_Java ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript) &&
|
2015-06-04 01:08:40 +08:00
|
|
|
Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements,
|
|
|
|
Keywords.kw_throws))
|
2014-11-03 03:16:41 +08:00
|
|
|
return 0;
|
2013-08-23 23:14:03 +08:00
|
|
|
}
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
return -1;
|
2013-08-23 23:14:03 +08:00
|
|
|
}
|
|
|
|
|
2013-05-31 22:56:12 +08:00
|
|
|
void addFakeParenthesis(FormatToken *Start, prec::Level Precedence) {
|
|
|
|
Start->FakeLParens.push_back(Precedence);
|
2013-09-06 16:08:14 +08:00
|
|
|
if (Precedence > prec::Unknown)
|
|
|
|
Start->StartsBinaryExpression = true;
|
|
|
|
if (Current) {
|
2014-11-14 20:31:14 +08:00
|
|
|
FormatToken *Previous = Current->Previous;
|
2014-12-03 22:02:59 +08:00
|
|
|
while (Previous->is(tok::comment) && Previous->Previous)
|
2014-11-14 20:31:14 +08:00
|
|
|
Previous = Previous->Previous;
|
|
|
|
++Previous->FakeRParens;
|
2013-09-06 16:08:14 +08:00
|
|
|
if (Precedence > prec::Unknown)
|
2014-11-14 20:31:14 +08:00
|
|
|
Previous->EndsBinaryExpression = true;
|
2013-09-06 16:08:14 +08:00
|
|
|
}
|
2013-05-31 22:56:12 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse unary operator expressions and surround them with fake
|
2013-08-23 23:14:03 +08:00
|
|
|
/// parentheses if appropriate.
|
|
|
|
void parseUnaryOperator() {
|
2017-11-02 02:20:41 +08:00
|
|
|
llvm::SmallVector<FormatToken *, 2> Tokens;
|
|
|
|
while (Current && Current->is(TT_UnaryOperator)) {
|
|
|
|
Tokens.push_back(Current);
|
|
|
|
next();
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
}
|
2017-11-02 02:20:41 +08:00
|
|
|
parse(PrecedenceArrowAndPeriod);
|
|
|
|
for (FormatToken *Token : llvm::reverse(Tokens))
|
|
|
|
// The actual precedence doesn't matter.
|
|
|
|
addFakeParenthesis(Token, prec::Unknown);
|
2013-08-23 23:14:03 +08:00
|
|
|
}
|
|
|
|
|
2013-05-31 22:56:12 +08:00
|
|
|
void parseConditionalExpr() {
|
2014-10-16 17:10:11 +08:00
|
|
|
while (Current && Current->isTrailingComment()) {
|
|
|
|
next();
|
|
|
|
}
|
2013-05-31 22:56:12 +08:00
|
|
|
FormatToken *Start = Current;
|
clang-format: Revamp builder-type call formatting.
Previously builder-type calls were only correctly recognized in
top-level calls.
This fixes llvm.org/PR16981.
Before:
someobj->Add((new util::filetools::Handler(dir))->OnEvent1(
NewPermanentCallback(this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
After:
someobj->Add((new util::filetools::Handler(dir))
->OnEvent1(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBA))
->OnEvent2(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBB))
->OnEvent3(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBC))
->OnEvent5(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBD))
->OnEvent6(NewPermanentCallback(
this, &HandlerHolderClass::EventHandlerCBE)));
llvm-svn: 189337
2013-08-27 19:09:05 +08:00
|
|
|
parse(prec::LogicalOr);
|
2013-05-31 22:56:12 +08:00
|
|
|
if (!Current || !Current->is(tok::question))
|
|
|
|
return;
|
|
|
|
next();
|
2014-11-14 21:03:40 +08:00
|
|
|
parse(prec::Assignment);
|
2014-11-25 18:05:17 +08:00
|
|
|
if (!Current || Current->isNot(TT_ConditionalExpr))
|
2013-05-31 22:56:12 +08:00
|
|
|
return;
|
|
|
|
next();
|
2014-11-14 21:03:40 +08:00
|
|
|
parse(prec::Assignment);
|
2013-05-31 22:56:12 +08:00
|
|
|
addFakeParenthesis(Start, prec::Conditional);
|
|
|
|
}
|
|
|
|
|
2014-09-04 22:58:30 +08:00
|
|
|
void next(bool SkipPastLeadingComments = true) {
|
2013-06-17 21:19:53 +08:00
|
|
|
if (Current)
|
|
|
|
Current = Current->Next;
|
2014-09-04 22:58:30 +08:00
|
|
|
while (Current &&
|
|
|
|
(Current->NewlinesBefore == 0 || SkipPastLeadingComments) &&
|
|
|
|
Current->isTrailingComment())
|
2013-05-29 22:47:47 +08:00
|
|
|
Current = Current->Next;
|
2013-02-08 23:28:42 +08:00
|
|
|
}
|
|
|
|
|
2014-11-03 03:16:41 +08:00
|
|
|
const FormatStyle &Style;
|
2014-11-04 20:41:02 +08:00
|
|
|
const AdditionalKeywords &Keywords;
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Current;
|
2013-02-08 23:28:42 +08:00
|
|
|
};
|
|
|
|
|
2013-07-01 12:03:19 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2015-01-10 07:25:06 +08:00
|
|
|
void TokenAnnotator::setCommentLineLevels(
|
|
|
|
SmallVectorImpl<AnnotatedLine *> &Lines) {
|
2014-05-09 16:15:10 +08:00
|
|
|
const AnnotatedLine *NextNonCommentLine = nullptr;
|
2013-11-06 03:10:03 +08:00
|
|
|
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
|
|
|
|
E = Lines.rend();
|
|
|
|
I != E; ++I) {
|
2017-07-12 23:21:43 +08:00
|
|
|
bool CommentLine = true;
|
2017-01-25 21:58:58 +08:00
|
|
|
for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) {
|
|
|
|
if (!Tok->is(tok::comment)) {
|
|
|
|
CommentLine = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-07-12 23:21:43 +08:00
|
|
|
|
2018-02-01 04:05:50 +08:00
|
|
|
// If the comment is currently aligned with the line immediately following
|
|
|
|
// it, that's probably intentional and we should keep it.
|
|
|
|
if (NextNonCommentLine && CommentLine &&
|
|
|
|
NextNonCommentLine->First->NewlinesBefore <= 1 &&
|
|
|
|
NextNonCommentLine->First->OriginalColumn ==
|
|
|
|
(*I)->First->OriginalColumn) {
|
|
|
|
// Align comments for preprocessor lines with the # in column 0.
|
|
|
|
// Otherwise, align with the next line.
|
|
|
|
(*I)->Level = (NextNonCommentLine->Type == LT_PreprocessorDirective ||
|
|
|
|
NextNonCommentLine->Type == LT_ImportStatement)
|
|
|
|
? 0
|
|
|
|
: NextNonCommentLine->Level;
|
2017-07-12 23:21:43 +08:00
|
|
|
} else {
|
2014-05-09 16:15:10 +08:00
|
|
|
NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr;
|
2017-07-12 23:21:43 +08:00
|
|
|
}
|
2013-11-06 03:10:03 +08:00
|
|
|
|
|
|
|
setCommentLineLevels((*I)->Children);
|
2013-09-06 15:54:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:23:00 +08:00
|
|
|
static unsigned maxNestingDepth(const AnnotatedLine &Line) {
|
|
|
|
unsigned Result = 0;
|
2017-09-20 17:51:03 +08:00
|
|
|
for (const auto *Tok = Line.First; Tok != nullptr; Tok = Tok->Next)
|
2016-10-31 21:23:00 +08:00
|
|
|
Result = std::max(Result, Tok->NestingLevel);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
void TokenAnnotator::annotate(AnnotatedLine &Line) {
|
2013-09-06 15:54:20 +08:00
|
|
|
for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
|
|
|
|
E = Line.Children.end();
|
2013-09-05 17:29:45 +08:00
|
|
|
I != E; ++I) {
|
|
|
|
annotate(**I);
|
|
|
|
}
|
2014-11-04 20:41:02 +08:00
|
|
|
AnnotatingParser Parser(Style, Line, Keywords);
|
2013-01-30 05:01:14 +08:00
|
|
|
Line.Type = Parser.parseLine();
|
2016-10-31 21:23:00 +08:00
|
|
|
|
|
|
|
// With very deep nesting, ExpressionParser uses lots of stack and the
|
|
|
|
// formatting algorithm is very slow. We're not going to do a good job here
|
|
|
|
// anyway - it's probably generated code being formatted by mistake.
|
|
|
|
// Just skip the whole line.
|
|
|
|
if (maxNestingDepth(Line) > 50)
|
|
|
|
Line.Type = LT_Invalid;
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Line.Type == LT_Invalid)
|
|
|
|
return;
|
|
|
|
|
2014-11-04 20:41:02 +08:00
|
|
|
ExpressionParser ExprParser(Style, Keywords, Line);
|
2013-02-08 23:28:42 +08:00
|
|
|
ExprParser.parse();
|
|
|
|
|
2015-06-17 17:43:56 +08:00
|
|
|
if (Line.startsWith(TT_ObjCMethodSpecifier))
|
2013-01-30 05:01:14 +08:00
|
|
|
Line.Type = LT_ObjCMethodDecl;
|
2015-06-17 17:43:56 +08:00
|
|
|
else if (Line.startsWith(TT_ObjCDecl))
|
2013-01-30 05:01:14 +08:00
|
|
|
Line.Type = LT_ObjCDecl;
|
2015-06-17 17:43:56 +08:00
|
|
|
else if (Line.startsWith(TT_ObjCProperty))
|
2013-01-30 05:01:14 +08:00
|
|
|
Line.Type = LT_ObjCProperty;
|
|
|
|
|
2013-05-29 22:47:47 +08:00
|
|
|
Line.First->SpacesRequiredBefore = 1;
|
|
|
|
Line.First->CanBreakBefore = Line.First->MustBreakBefore;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
2014-07-09 15:50:33 +08:00
|
|
|
// This function heuristically determines whether 'Current' starts the name of a
|
|
|
|
// function declaration.
|
2016-04-18 19:31:21 +08:00
|
|
|
static bool isFunctionDeclarationName(const FormatToken &Current,
|
|
|
|
const AnnotatedLine &Line) {
|
2017-09-20 17:51:03 +08:00
|
|
|
auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
|
2015-07-16 03:11:58 +08:00
|
|
|
for (; Next; Next = Next->Next) {
|
|
|
|
if (Next->is(TT_OverloadedOperatorLParen))
|
|
|
|
return Next;
|
|
|
|
if (Next->is(TT_OverloadedOperator))
|
|
|
|
continue;
|
|
|
|
if (Next->isOneOf(tok::kw_new, tok::kw_delete)) {
|
|
|
|
// For 'new[]' and 'delete[]'.
|
2017-09-20 17:51:03 +08:00
|
|
|
if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next &&
|
|
|
|
Next->Next->Next->is(tok::r_square))
|
2015-07-16 03:11:58 +08:00
|
|
|
Next = Next->Next->Next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-09 15:50:33 +08:00
|
|
|
break;
|
2015-07-16 03:11:58 +08:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
};
|
|
|
|
|
2016-04-18 19:31:21 +08:00
|
|
|
// Find parentheses of parameter list.
|
2015-07-16 03:11:58 +08:00
|
|
|
const FormatToken *Next = Current.Next;
|
|
|
|
if (Current.is(tok::kw_operator)) {
|
|
|
|
if (Current.Previous && Current.Previous->is(tok::coloncolon))
|
|
|
|
return false;
|
|
|
|
Next = skipOperatorName(Next);
|
|
|
|
} else {
|
|
|
|
if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0)
|
2014-07-09 15:50:33 +08:00
|
|
|
return false;
|
2015-07-16 03:11:58 +08:00
|
|
|
for (; Next; Next = Next->Next) {
|
|
|
|
if (Next->is(TT_TemplateOpener)) {
|
|
|
|
Next = Next->MatchingParen;
|
|
|
|
} else if (Next->is(tok::coloncolon)) {
|
|
|
|
Next = Next->Next;
|
|
|
|
if (!Next)
|
|
|
|
return false;
|
|
|
|
if (Next->is(tok::kw_operator)) {
|
|
|
|
Next = skipOperatorName(Next->Next);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!Next->is(tok::identifier))
|
|
|
|
return false;
|
|
|
|
} else if (Next->is(tok::l_paren)) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-09 15:50:33 +08:00
|
|
|
}
|
|
|
|
}
|
2015-07-16 03:11:58 +08:00
|
|
|
|
2017-02-08 05:38:16 +08:00
|
|
|
// Check whether parameter list can belong to a function declaration.
|
2016-04-18 19:31:21 +08:00
|
|
|
if (!Next || !Next->is(tok::l_paren) || !Next->MatchingParen)
|
2014-07-09 15:50:33 +08:00
|
|
|
return false;
|
2016-04-18 19:31:21 +08:00
|
|
|
// If the lines ends with "{", this is likely an function definition.
|
|
|
|
if (Line.Last->is(tok::l_brace))
|
|
|
|
return true;
|
2014-07-09 15:50:33 +08:00
|
|
|
if (Next->Next == Next->MatchingParen)
|
2016-04-18 19:31:21 +08:00
|
|
|
return true; // Empty parentheses.
|
|
|
|
// If there is an &/&& after the r_paren, this is likely a function.
|
|
|
|
if (Next->MatchingParen->Next &&
|
|
|
|
Next->MatchingParen->Next->is(TT_PointerOrReference))
|
2014-07-09 15:50:33 +08:00
|
|
|
return true;
|
2015-01-19 18:52:16 +08:00
|
|
|
for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen;
|
2014-07-09 15:50:33 +08:00
|
|
|
Tok = Tok->Next) {
|
2017-02-08 05:38:16 +08:00
|
|
|
if (Tok->is(tok::l_paren) && Tok->MatchingParen) {
|
|
|
|
Tok = Tok->MatchingParen;
|
|
|
|
continue;
|
|
|
|
}
|
2014-07-09 15:50:33 +08:00
|
|
|
if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
|
2016-04-18 19:31:21 +08:00
|
|
|
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis))
|
2014-07-09 15:50:33 +08:00
|
|
|
return true;
|
2015-04-23 21:58:40 +08:00
|
|
|
if (Tok->isOneOf(tok::l_brace, tok::string_literal, TT_ObjCMethodExpr) ||
|
|
|
|
Tok->Tok.isLiteral())
|
2014-07-09 15:50:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-19 06:20:15 +08:00
|
|
|
bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {
|
|
|
|
assert(Line.MightBeFunctionDecl);
|
|
|
|
|
|
|
|
if ((Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevel ||
|
|
|
|
Style.AlwaysBreakAfterReturnType ==
|
|
|
|
FormatStyle::RTBS_TopLevelDefinitions) &&
|
|
|
|
Line.Level > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (Style.AlwaysBreakAfterReturnType) {
|
|
|
|
case FormatStyle::RTBS_None:
|
|
|
|
return false;
|
|
|
|
case FormatStyle::RTBS_All:
|
|
|
|
case FormatStyle::RTBS_TopLevel:
|
|
|
|
return true;
|
|
|
|
case FormatStyle::RTBS_AllDefinitions:
|
|
|
|
case FormatStyle::RTBS_TopLevelDefinitions:
|
|
|
|
return Line.mightBeFunctionDefinition();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
|
2014-05-22 16:36:53 +08:00
|
|
|
for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
|
|
|
|
E = Line.Children.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
calculateFormattingInformation(**I);
|
|
|
|
}
|
|
|
|
|
2013-09-10 17:38:25 +08:00
|
|
|
Line.First->TotalLength =
|
2017-10-30 22:01:50 +08:00
|
|
|
Line.First->IsMultiline ? Style.ColumnLimit
|
|
|
|
: Line.FirstStartColumn + Line.First->ColumnWidth;
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Current = Line.First->Next;
|
2013-11-08 01:52:51 +08:00
|
|
|
bool InFunctionDecl = Line.MightBeFunctionDecl;
|
2014-05-09 16:15:10 +08:00
|
|
|
while (Current) {
|
2016-04-18 19:31:21 +08:00
|
|
|
if (isFunctionDeclarationName(*Current, Line))
|
2014-07-09 15:50:33 +08:00
|
|
|
Current->Type = TT_FunctionDeclarationName;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Current->is(TT_LineComment)) {
|
2014-03-10 23:06:25 +08:00
|
|
|
if (Current->Previous->BlockKind == BK_BracedInit &&
|
|
|
|
Current->Previous->opensScope())
|
2013-12-20 05:41:37 +08:00
|
|
|
Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1;
|
|
|
|
else
|
|
|
|
Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
|
2014-03-21 19:58:45 +08:00
|
|
|
|
|
|
|
// If we find a trailing comment, iterate backwards to determine whether
|
|
|
|
// it seems to relate to a specific parameter. If so, break before that
|
|
|
|
// parameter to avoid changing the comment's meaning. E.g. don't move 'b'
|
|
|
|
// to the previous line in:
|
|
|
|
// SomeFunction(a,
|
|
|
|
// b, // comment
|
|
|
|
// c);
|
2014-03-21 20:15:40 +08:00
|
|
|
if (!Current->HasUnescapedNewline) {
|
2014-03-21 19:58:45 +08:00
|
|
|
for (FormatToken *Parameter = Current->Previous; Parameter;
|
|
|
|
Parameter = Parameter->Previous) {
|
|
|
|
if (Parameter->isOneOf(tok::comment, tok::r_brace))
|
|
|
|
break;
|
|
|
|
if (Parameter->Previous && Parameter->Previous->is(tok::comma)) {
|
2014-11-25 18:05:17 +08:00
|
|
|
if (!Parameter->Previous->is(TT_CtorInitializerComma) &&
|
2014-03-21 19:58:45 +08:00
|
|
|
Parameter->HasUnescapedNewline)
|
|
|
|
Parameter->MustBreakBefore = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-23 15:29:06 +08:00
|
|
|
} else if (Current->SpacesRequiredBefore == 0 &&
|
2014-05-06 22:12:21 +08:00
|
|
|
spaceRequiredBefore(Line, *Current)) {
|
2013-10-12 05:43:05 +08:00
|
|
|
Current->SpacesRequiredBefore = 1;
|
2013-12-20 05:41:37 +08:00
|
|
|
}
|
2013-02-06 22:22:40 +08:00
|
|
|
|
2013-09-17 17:52:48 +08:00
|
|
|
Current->MustBreakBefore =
|
|
|
|
Current->MustBreakBefore || mustBreakBefore(Line, *Current);
|
|
|
|
|
2015-12-19 06:20:15 +08:00
|
|
|
if (!Current->MustBreakBefore && InFunctionDecl &&
|
|
|
|
Current->is(TT_FunctionDeclarationName))
|
|
|
|
Current->MustBreakBefore = mustBreakForReturnType(Line);
|
2014-08-05 20:16:31 +08:00
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
Current->CanBreakBefore =
|
|
|
|
Current->MustBreakBefore || canBreakBefore(Line, *Current);
|
2014-05-22 16:36:53 +08:00
|
|
|
unsigned ChildSize = 0;
|
|
|
|
if (Current->Previous->Children.size() == 1) {
|
|
|
|
FormatToken &LastOfChild = *Current->Previous->Children[0]->Last;
|
|
|
|
ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit
|
|
|
|
: LastOfChild.TotalLength + 1;
|
|
|
|
}
|
2015-01-10 07:25:06 +08:00
|
|
|
const FormatToken *Prev = Current->Previous;
|
2014-10-28 00:31:46 +08:00
|
|
|
if (Current->MustBreakBefore || Prev->Children.size() > 1 ||
|
|
|
|
(Prev->Children.size() == 1 &&
|
|
|
|
Prev->Children[0]->First->MustBreakBefore) ||
|
2013-09-10 17:38:25 +08:00
|
|
|
Current->IsMultiline)
|
2014-10-28 00:31:46 +08:00
|
|
|
Current->TotalLength = Prev->TotalLength + Style.ColumnLimit;
|
2013-02-06 22:22:40 +08:00
|
|
|
else
|
2014-10-28 00:31:46 +08:00
|
|
|
Current->TotalLength = Prev->TotalLength + Current->ColumnWidth +
|
|
|
|
ChildSize + Current->SpacesRequiredBefore;
|
2013-11-08 01:52:51 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Current->is(TT_CtorInitializerColon))
|
2013-11-08 01:52:51 +08:00
|
|
|
InFunctionDecl = false;
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
// FIXME: Only calculate this if CanBreakBefore is true once static
|
|
|
|
// initializers etc. are sorted out.
|
|
|
|
// FIXME: Move magic numbers to a better place.
|
2013-11-08 01:52:51 +08:00
|
|
|
Current->SplitPenalty = 20 * Current->BindingStrength +
|
|
|
|
splitPenalty(Line, *Current, InFunctionDecl);
|
2013-02-06 22:22:40 +08:00
|
|
|
|
2013-05-29 22:47:47 +08:00
|
|
|
Current = Current->Next;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
2013-04-09 04:33:42 +08:00
|
|
|
|
2013-05-22 20:51:29 +08:00
|
|
|
calculateUnbreakableTailLengths(Line);
|
2017-01-31 19:25:01 +08:00
|
|
|
unsigned IndentLevel = Line.Level;
|
2014-05-09 16:15:10 +08:00
|
|
|
for (Current = Line.First; Current != nullptr; Current = Current->Next) {
|
clang-format: Add column layout formatting for braced lists
With this patch, braced lists (with more than 3 elements are formatted in a
column layout if possible). E.g.:
static const uint16_t CallerSavedRegs64Bit[] = {
X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,
X86::R8, X86::R9, X86::R10, X86::R11, 0
};
Required other changes:
- FormatTokens can now have a special role that contains extra data and can do
special formattings. A comma separated list is currently the only
implementation.
- Move penalty calculation entirely into ContinuationIndenter (there was a last
piece still in UnwrappedLineFormatter).
Review: http://llvm-reviews.chandlerc.com/D1457
llvm-svn: 189018
2013-08-22 23:00:41 +08:00
|
|
|
if (Current->Role)
|
|
|
|
Current->Role->precomputeFormattingInfos(Current);
|
2017-01-31 19:25:01 +08:00
|
|
|
if (Current->MatchingParen &&
|
|
|
|
Current->MatchingParen->opensBlockOrBlockTypeList(Style)) {
|
|
|
|
assert(IndentLevel > 0);
|
|
|
|
--IndentLevel;
|
|
|
|
}
|
|
|
|
Current->IndentLevel = IndentLevel;
|
|
|
|
if (Current->opensBlockOrBlockTypeList(Style))
|
|
|
|
++IndentLevel;
|
clang-format: Add column layout formatting for braced lists
With this patch, braced lists (with more than 3 elements are formatted in a
column layout if possible). E.g.:
static const uint16_t CallerSavedRegs64Bit[] = {
X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,
X86::R8, X86::R9, X86::R10, X86::R11, 0
};
Required other changes:
- FormatTokens can now have a special role that contains extra data and can do
special formattings. A comma separated list is currently the only
implementation.
- Move penalty calculation entirely into ContinuationIndenter (there was a last
piece still in UnwrappedLineFormatter).
Review: http://llvm-reviews.chandlerc.com/D1457
llvm-svn: 189018
2013-08-22 23:00:41 +08:00
|
|
|
}
|
|
|
|
|
2018-05-15 21:30:56 +08:00
|
|
|
LLVM_DEBUG({ printDebugInfo(Line); });
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
2013-05-22 20:51:29 +08:00
|
|
|
void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) {
|
|
|
|
unsigned UnbreakableTailLength = 0;
|
2013-05-29 22:47:47 +08:00
|
|
|
FormatToken *Current = Line.Last;
|
2014-05-09 16:15:10 +08:00
|
|
|
while (Current) {
|
2013-05-22 20:51:29 +08:00
|
|
|
Current->UnbreakableTailLength = UnbreakableTailLength;
|
|
|
|
if (Current->CanBreakBefore ||
|
|
|
|
Current->isOneOf(tok::comment, tok::string_literal)) {
|
|
|
|
UnbreakableTailLength = 0;
|
|
|
|
} else {
|
|
|
|
UnbreakableTailLength +=
|
2013-09-10 17:38:25 +08:00
|
|
|
Current->ColumnWidth + Current->SpacesRequiredBefore;
|
2013-05-22 20:51:29 +08:00
|
|
|
}
|
2013-05-29 22:47:47 +08:00
|
|
|
Current = Current->Previous;
|
2013-05-22 20:51:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
|
2013-11-08 01:52:51 +08:00
|
|
|
const FormatToken &Tok,
|
|
|
|
bool InFunctionDecl) {
|
2013-05-29 22:47:47 +08:00
|
|
|
const FormatToken &Left = *Tok.Previous;
|
|
|
|
const FormatToken &Right = Tok;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2013-05-28 19:30:49 +08:00
|
|
|
if (Left.is(tok::semi))
|
|
|
|
return 0;
|
2014-11-14 18:15:56 +08:00
|
|
|
|
|
|
|
if (Style.Language == FormatStyle::LK_Java) {
|
2014-11-26 20:31:19 +08:00
|
|
|
if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws))
|
2014-11-14 18:15:56 +08:00
|
|
|
return 1;
|
|
|
|
if (Right.is(Keywords.kw_implements))
|
|
|
|
return 2;
|
|
|
|
if (Left.is(tok::comma) && Left.NestingLevel == 0)
|
|
|
|
return 3;
|
2014-11-27 23:37:42 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript) {
|
2015-05-08 16:38:52 +08:00
|
|
|
if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma))
|
2014-11-27 23:37:42 +08:00
|
|
|
return 100;
|
2015-07-10 21:39:26 +08:00
|
|
|
if (Left.is(TT_JsTypeColon))
|
2016-01-08 18:51:24 +08:00
|
|
|
return 35;
|
2016-08-25 18:13:21 +08:00
|
|
|
if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
|
|
|
|
(Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
|
|
|
|
return 100;
|
2017-08-02 01:35:57 +08:00
|
|
|
// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
|
|
|
|
if (Left.opensScope() && Right.closesScope())
|
|
|
|
return 200;
|
2014-11-14 18:15:56 +08:00
|
|
|
}
|
|
|
|
|
clang-format: Keep string-literal-label + value pairs on a line.
We have previously done that for <<-operators. This patch also adds
this logic for "," and "+".
Before:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " +
aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ",
aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
After:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
llvm-svn: 289531
2016-12-13 19:16:42 +08:00
|
|
|
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
|
2013-05-28 19:30:49 +08:00
|
|
|
return 1;
|
2014-01-19 17:04:08 +08:00
|
|
|
if (Right.is(tok::l_square)) {
|
2015-12-30 20:23:00 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Proto)
|
2014-01-19 17:04:08 +08:00
|
|
|
return 1;
|
2015-12-30 20:23:00 +08:00
|
|
|
if (Left.is(tok::r_square))
|
2016-03-01 12:19:55 +08:00
|
|
|
return 200;
|
2015-05-13 16:47:16 +08:00
|
|
|
// Slightly prefer formatting local lambda definitions like functions.
|
|
|
|
if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal))
|
2016-01-04 15:29:40 +08:00
|
|
|
return 35;
|
2015-06-03 16:57:36 +08:00
|
|
|
if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
|
2017-06-19 22:41:21 +08:00
|
|
|
TT_ArrayInitializerLSquare,
|
2018-03-12 23:42:38 +08:00
|
|
|
TT_DesignatedInitializerLSquare, TT_AttributeSquare))
|
2014-06-10 21:27:57 +08:00
|
|
|
return 500;
|
2014-01-19 17:04:08 +08:00
|
|
|
}
|
2014-11-14 18:15:56 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
|
|
|
|
Right.is(tok::kw_operator)) {
|
2015-06-17 17:43:56 +08:00
|
|
|
if (Line.startsWith(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
|
Allow breaking between a type and name in variable declarations.
This fixes llvm.org/PR14967 and is generall necessary to avoid
situations where the column limit is exceeded. The challenge is
restricting such lines splits, otherwise clang-format suddenly starts
breaking at bad places.
Before:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string,
SomeOtherTemplateParameter> &ReallyReallyLongParameterName,
const SomeType<string,
SomeOtherTemplateParameter> &AnotherLongParameterName) {}
After:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string, SomeOtherTemplateParameter> &
ReallyReallyLongParameterName,
const SomeType<string, SomeOtherTemplateParameter> &
AnotherLongParameterName) {}
llvm-svn: 175999
2013-02-25 02:54:32 +08:00
|
|
|
return 3;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_StartOfName))
|
2015-05-15 17:58:11 +08:00
|
|
|
return 110;
|
clang-format: Be more conservative about braced list column layout.
Specifically disable it for nested braced lists as it commonly can look
really weird. Eventually, we'll want to become smarter and format some of
the nested lists better.
Before:
SomeStruct my_struct_array = {
{ aaaaaa, aaaaaaaa, aaaaaaaaaa, aaaaaaaaa, aaaaaaaaa,
aaaaaaaaaa, aaaaaaaaaa, aaaaaaa, aaa },
{ aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaa },
{ aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaa, a, aaaaaaaaaa,
aaaaaaaaa, aaa },
};
After:
SomeStruct my_struct_array = {
{ aaaaaa, aaaaaaaa, aaaaaaaaaa, aaaaaaaaa, aaaaaaaaa, aaaaaaaaaa,
aaaaaaaaaaaa, aaaaaaa, aaa },
{ aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaa },
{ aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaa, a, aaaaaaaaaa, aaaaaaaaa, aaa },
};
llvm-svn: 196783
2013-12-09 22:40:19 +08:00
|
|
|
if (InFunctionDecl && Right.NestingLevel == 0)
|
Allow breaking between a type and name in variable declarations.
This fixes llvm.org/PR14967 and is generall necessary to avoid
situations where the column limit is exceeded. The challenge is
restricting such lines splits, otherwise clang-format suddenly starts
breaking at bad places.
Before:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string,
SomeOtherTemplateParameter> &ReallyReallyLongParameterName,
const SomeType<string,
SomeOtherTemplateParameter> &AnotherLongParameterName) {}
After:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string, SomeOtherTemplateParameter> &
ReallyReallyLongParameterName,
const SomeType<string, SomeOtherTemplateParameter> &
AnotherLongParameterName) {}
llvm-svn: 175999
2013-02-25 02:54:32 +08:00
|
|
|
return Style.PenaltyReturnTypeOnItsOwnLine;
|
2013-08-19 18:16:18 +08:00
|
|
|
return 200;
|
Allow breaking between a type and name in variable declarations.
This fixes llvm.org/PR14967 and is generall necessary to avoid
situations where the column limit is exceeded. The challenge is
restricting such lines splits, otherwise clang-format suddenly starts
breaking at bad places.
Before:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string,
SomeOtherTemplateParameter> &ReallyReallyLongParameterName,
const SomeType<string,
SomeOtherTemplateParameter> &AnotherLongParameterName) {}
After:
ReallyLongReturnType<TemplateParam1, TemplateParam2>
ReallyReallyLongFunctionName(
const std::string &SomeParameter,
const SomeType<string, SomeOtherTemplateParameter> &
ReallyReallyLongParameterName,
const SomeType<string, SomeOtherTemplateParameter> &
AnotherLongParameterName) {}
llvm-svn: 175999
2013-02-25 02:54:32 +08:00
|
|
|
}
|
2015-03-12 23:04:53 +08:00
|
|
|
if (Right.is(TT_PointerOrReference))
|
2015-03-19 17:40:16 +08:00
|
|
|
return 190;
|
2015-06-05 21:18:09 +08:00
|
|
|
if (Right.is(TT_LambdaArrow))
|
2015-03-02 18:35:13 +08:00
|
|
|
return 110;
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Left.is(tok::equal) && Right.is(tok::l_brace))
|
2017-03-14 08:40:32 +08:00
|
|
|
return 160;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_CastRParen))
|
2013-07-05 15:58:34 +08:00
|
|
|
return 100;
|
2014-01-22 16:04:52 +08:00
|
|
|
if (Left.is(tok::coloncolon) ||
|
|
|
|
(Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto))
|
2013-01-30 05:01:14 +08:00
|
|
|
return 500;
|
2013-04-06 01:22:09 +08:00
|
|
|
if (Left.isOneOf(tok::kw_class, tok::kw_struct))
|
|
|
|
return 5000;
|
2016-05-27 16:59:34 +08:00
|
|
|
if (Left.is(tok::comment))
|
|
|
|
return 1000;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2017-09-20 17:51:03 +08:00
|
|
|
if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon,
|
|
|
|
TT_CtorInitializerColon))
|
2013-02-26 21:18:08 +08:00
|
|
|
return 2;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
clang-format: Format segments of builder-type calls one per line.
This fixes llvm.org/PR14818.
Before:
return llvm::StringSwitch<Reference::Kind>(name)
.StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
.StartsWith(".eh_frame", ORDER_EH_FRAME)
.StartsWith(".init", ORDER_INIT).StartsWith(".fini", ORDER_FINI)
.StartsWith(".hash", ORDER_HASH).Default(ORDER_TEXT);
After:
return llvm::StringSwitch<Reference::Kind>(name)
.StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
.StartsWith(".eh_frame", ORDER_EH_FRAME)
.StartsWith(".init", ORDER_INIT)
.StartsWith(".fini", ORDER_FINI)
.StartsWith(".hash", ORDER_HASH)
.Default(ORDER_TEXT);
llvm-svn: 189353
2013-08-27 22:24:43 +08:00
|
|
|
if (Right.isMemberAccess()) {
|
2015-12-08 03:50:48 +08:00
|
|
|
// Breaking before the "./->" of a chained call/member access is reasonably
|
|
|
|
// cheap, as formatting those with one call per line is generally
|
|
|
|
// desirable. In particular, it should be cheaper to break before the call
|
|
|
|
// than it is to break inside a call's parameters, which could lead to weird
|
|
|
|
// "hanging" indents. The exception is the very last "./->" to support this
|
|
|
|
// frequent pattern:
|
|
|
|
//
|
|
|
|
// aaaaaaaa.aaaaaaaa.bbbbbbb().ccccccccccccccccccccc(
|
|
|
|
// dddddddd);
|
|
|
|
//
|
|
|
|
// which might otherwise be blown up onto many lines. Here, clang-format
|
|
|
|
// won't produce "hanging" indents anyway as there is no other trailing
|
|
|
|
// call.
|
2016-01-05 21:03:50 +08:00
|
|
|
//
|
|
|
|
// Also apply higher penalty is not a call as that might lead to a wrapping
|
|
|
|
// like:
|
|
|
|
//
|
|
|
|
// aaaaaaa
|
|
|
|
// .aaaaaaaaa.bbbbbbbb(cccccccc);
|
|
|
|
return !Right.NextOperator || !Right.NextOperator->Previous->closesScope()
|
|
|
|
? 150
|
|
|
|
: 35;
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_TrailingAnnotation) &&
|
2014-06-02 17:52:08 +08:00
|
|
|
(!Right.Next || Right.Next->isNot(tok::l_paren))) {
|
2014-10-11 16:24:56 +08:00
|
|
|
// Moving trailing annotations to the next line is fine for ObjC method
|
|
|
|
// declarations.
|
2015-06-17 17:43:56 +08:00
|
|
|
if (Line.startsWith(TT_ObjCMethodSpecifier))
|
2014-10-11 16:24:56 +08:00
|
|
|
return 10;
|
2014-02-17 15:57:46 +08:00
|
|
|
// Generally, breaking before a trailing annotation is bad unless it is
|
|
|
|
// function-like. It seems to be especially preferable to keep standard
|
|
|
|
// annotations (i.e. "const", "final" and "override") on the same line.
|
2013-12-16 23:01:54 +08:00
|
|
|
// Use a slightly higher penalty after ")" so that annotations like
|
|
|
|
// "const override" are kept together.
|
2014-04-09 18:01:49 +08:00
|
|
|
bool is_short_annotation = Right.TokenText.size() < 10;
|
2014-05-09 21:11:16 +08:00
|
|
|
return (Left.is(tok::r_paren) ? 100 : 120) + (is_short_annotation ? 50 : 0);
|
2013-12-16 23:01:54 +08:00
|
|
|
}
|
2013-05-22 16:28:26 +08:00
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
// In for-loops, prefer breaking at ',' and ';'.
|
2015-06-17 17:43:56 +08:00
|
|
|
if (Line.startsWith(tok::kw_for) && Left.is(tok::equal))
|
Allow breaking between type and name in for loops.
This fixes llvm.org/PR15033.
Also: Always break before a parameter, if the previous parameter was
split over multiple lines. This was necessary to make the right
decisions in for-loops, almost always makes the code more readable and
also fixes llvm.org/PR14873.
Before:
for (llvm::ArrayRef<NamedDecl *>::iterator I = FD->getDeclsInPrototypeScope()
.begin(), E = FD->getDeclsInPrototypeScope().end();
I != E; ++I) {
}
foo(bar(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
ccccccccccccccccccccccccccccc), d, bar(e, f));
After:
for (llvm::ArrayRef<NamedDecl *>::iterator
I = FD->getDeclsInPrototypeScope().begin(),
E = FD->getDeclsInPrototypeScope().end();
I != E; ++I) {
}
foo(bar(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
ccccccccccccccccccccccccccccc),
d, bar(e, f));
llvm-svn: 175741
2013-02-21 23:00:29 +08:00
|
|
|
return 4;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
|
|
|
// In Objective-C method expressions, prefer breaking before "param:" over
|
|
|
|
// breaking after it.
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_SelectorName))
|
2013-01-30 05:01:14 +08:00
|
|
|
return 0;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(tok::colon) && Left.is(TT_ObjCMethodExpr))
|
2013-11-23 22:27:27 +08:00
|
|
|
return Line.MightBeFunctionDecl ? 50 : 500;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2018-04-12 23:11:55 +08:00
|
|
|
// In Objective-C type declarations, avoid breaking after the category's
|
|
|
|
// open paren (we'll prefer breaking after the protocol list's opening
|
|
|
|
// angle bracket, if present).
|
|
|
|
if (Line.Type == LT_ObjCDecl && Left.is(tok::l_paren) && Left.Previous &&
|
|
|
|
Left.Previous->isOneOf(tok::identifier, tok::greater))
|
|
|
|
return 500;
|
|
|
|
|
2015-10-27 20:38:37 +08:00
|
|
|
if (Left.is(tok::l_paren) && InFunctionDecl &&
|
|
|
|
Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign)
|
2013-04-11 22:29:13 +08:00
|
|
|
return 100;
|
2015-07-08 00:09:39 +08:00
|
|
|
if (Left.is(tok::l_paren) && Left.Previous &&
|
2017-09-20 17:51:03 +08:00
|
|
|
(Left.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
|
|
|
|
Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if)))
|
2015-02-26 17:49:08 +08:00
|
|
|
return 1000;
|
2013-12-27 14:39:56 +08:00
|
|
|
if (Left.is(tok::equal) && InFunctionDecl)
|
|
|
|
return 110;
|
2014-08-08 20:00:13 +08:00
|
|
|
if (Right.is(tok::r_brace))
|
|
|
|
return 1;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_TemplateOpener))
|
2014-08-15 13:00:39 +08:00
|
|
|
return 100;
|
2014-11-19 07:55:27 +08:00
|
|
|
if (Left.opensScope()) {
|
2015-10-27 20:38:37 +08:00
|
|
|
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign)
|
2014-11-19 07:55:27 +08:00
|
|
|
return 0;
|
clang-format: tweak formatting of variable initialization blocks
Summary:
This patch changes the behavior of PenaltyBreakBeforeFirstCallParameter
so that is does not apply after a brace, when Cpp11BracedListStyle is
false.
This way, variable initialization is wrapped more like an initializer
than like a function call, which is more consistent with user
expectations for this braced list style.
With PenaltyBreakBeforeFirstCallParameter=200, this gives the following
code: (with Cpp11BracedListStyle=false)
Before :
const std::unordered_map<std::string, int> Something::MyHashTable =
{ { "aaaaaaaaaaaaaaaaaaaaa", 0 },
{ "bbbbbbbbbbbbbbbbbbbbb", 1 },
{ "ccccccccccccccccccccc", 2 } };
After :
const std::unordered_set<std::string> Something::MyUnorderedSet = {
{ "aaaaaaaaaaaaaaaaaaaaa", 0 },
{ "bbbbbbbbbbbbbbbbbbbbb", 1 },
{ "ccccccccccccccccccccc", 2 }
};
Reviewers: krasimir, djasper, klimek
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D43290
llvm-svn: 332434
2018-05-16 16:03:52 +08:00
|
|
|
if (Left.is(tok::l_brace) && !Style.Cpp11BracedListStyle)
|
|
|
|
return 19;
|
2013-10-25 22:29:37 +08:00
|
|
|
return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter
|
|
|
|
: 19;
|
2014-11-19 07:55:27 +08:00
|
|
|
}
|
2015-01-14 18:36:31 +08:00
|
|
|
if (Left.is(TT_JavaAnnotation))
|
|
|
|
return 50;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
clang-format: Keep string-literal-label + value pairs on a line.
We have previously done that for <<-operators. This patch also adds
this logic for "," and "+".
Before:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " +
aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ",
aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
After:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
llvm-svn: 289531
2016-12-13 19:16:42 +08:00
|
|
|
if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous &&
|
|
|
|
Left.Previous->isLabelString() &&
|
2016-12-20 23:27:46 +08:00
|
|
|
(Left.NextOperator || Left.OperatorIndex != 0))
|
2017-12-14 23:16:18 +08:00
|
|
|
return 50;
|
2016-12-20 23:27:46 +08:00
|
|
|
if (Right.is(tok::plus) && Left.isLabelString() &&
|
|
|
|
(Right.NextOperator || Right.OperatorIndex != 0))
|
|
|
|
return 25;
|
clang-format: Keep string-literal-label + value pairs on a line.
We have previously done that for <<-operators. This patch also adds
this logic for "," and "+".
Before:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " +
aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ",
aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
After:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
llvm-svn: 289531
2016-12-13 19:16:42 +08:00
|
|
|
if (Left.is(tok::comma))
|
|
|
|
return 1;
|
2016-12-20 23:27:46 +08:00
|
|
|
if (Right.is(tok::lessless) && Left.isLabelString() &&
|
clang-format: Keep string-literal-label + value pairs on a line.
We have previously done that for <<-operators. This patch also adds
this logic for "," and "+".
Before:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " +
aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ",
aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
After:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
llvm-svn: 289531
2016-12-13 19:16:42 +08:00
|
|
|
(Right.NextOperator || Right.OperatorIndex != 1))
|
|
|
|
return 25;
|
2016-12-19 19:14:23 +08:00
|
|
|
if (Right.is(tok::lessless)) {
|
|
|
|
// Breaking at a << is really cheap.
|
|
|
|
if (!Left.is(tok::r_paren) || Right.OperatorIndex > 0)
|
|
|
|
// Slightly prefer to break before the first one in log-like statements.
|
|
|
|
return 2;
|
|
|
|
return 1;
|
|
|
|
}
|
2018-05-16 16:25:03 +08:00
|
|
|
if (Left.ClosesTemplateDeclaration)
|
|
|
|
return Style.PenaltyBreakTemplateDeclaration;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_ConditionalExpr))
|
2013-02-26 21:59:14 +08:00
|
|
|
return prec::Conditional;
|
2013-05-29 22:47:47 +08:00
|
|
|
prec::Level Level = Left.getPrecedence();
|
2017-05-22 16:28:17 +08:00
|
|
|
if (Level == prec::Unknown)
|
|
|
|
Level = Right.getPrecedence();
|
|
|
|
if (Level == prec::Assignment)
|
|
|
|
return Style.PenaltyBreakAssignment;
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Level != prec::Unknown)
|
|
|
|
return Level;
|
2013-03-02 00:48:32 +08:00
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
2013-05-29 22:47:47 +08:00
|
|
|
const FormatToken &Left,
|
|
|
|
const FormatToken &Right) {
|
2014-05-06 22:12:21 +08:00
|
|
|
if (Left.is(tok::kw_return) && Right.isNot(tok::semi))
|
|
|
|
return true;
|
2017-09-26 06:42:49 +08:00
|
|
|
if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java)
|
|
|
|
return true;
|
2014-01-28 23:20:33 +08:00
|
|
|
if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
|
|
|
|
Left.Tok.getObjCKeywordID() == tok::objc_property)
|
|
|
|
return true;
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Right.is(tok::hashhash))
|
|
|
|
return Left.is(tok::hash);
|
2013-03-13 22:41:29 +08:00
|
|
|
if (Left.isOneOf(tok::hashhash, tok::hash))
|
2013-01-30 05:01:14 +08:00
|
|
|
return Right.is(tok::hash);
|
2013-08-20 20:36:34 +08:00
|
|
|
if (Left.is(tok::l_paren) && Right.is(tok::r_paren))
|
|
|
|
return Style.SpaceInEmptyParentheses;
|
|
|
|
if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
|
2015-01-10 07:25:06 +08:00
|
|
|
return (Right.is(TT_CastRParen) ||
|
2014-11-25 18:05:17 +08:00
|
|
|
(Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen)))
|
2013-08-20 20:36:34 +08:00
|
|
|
? Style.SpacesInCStyleCastParentheses
|
|
|
|
: Style.SpacesInParentheses;
|
|
|
|
if (Right.isOneOf(tok::semi, tok::comma))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2018-04-12 23:11:51 +08:00
|
|
|
if (Right.is(tok::less) && Line.Type == LT_ObjCDecl) {
|
|
|
|
bool IsLightweightGeneric =
|
|
|
|
Right.MatchingParen && Right.MatchingParen->Next &&
|
|
|
|
Right.MatchingParen->Next->is(tok::colon);
|
|
|
|
return !IsLightweightGeneric && Style.ObjCSpaceBeforeProtocolList;
|
|
|
|
}
|
2016-08-09 22:24:40 +08:00
|
|
|
if (Right.is(tok::less) && Left.is(tok::kw_template))
|
|
|
|
return Style.SpaceAfterTemplateKeyword;
|
2013-03-13 22:41:29 +08:00
|
|
|
if (Left.isOneOf(tok::exclaim, tok::tilde))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
|
|
|
if (Left.is(tok::at) &&
|
2013-03-13 22:41:29 +08:00
|
|
|
Right.isOneOf(tok::identifier, tok::string_literal, tok::char_constant,
|
|
|
|
tok::numeric_constant, tok::l_paren, tok::l_brace,
|
|
|
|
tok::kw_true, tok::kw_false))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2016-01-04 15:28:12 +08:00
|
|
|
if (Left.is(tok::colon))
|
|
|
|
return !Left.is(TT_ObjCMethodExpr);
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Left.is(tok::coloncolon))
|
|
|
|
return false;
|
2018-02-06 19:34:34 +08:00
|
|
|
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) {
|
|
|
|
if (Style.Language == FormatStyle::LK_TextProto ||
|
|
|
|
(Style.Language == FormatStyle::LK_Proto &&
|
|
|
|
(Left.is(TT_DictLiteral) || Right.is(TT_DictLiteral)))) {
|
|
|
|
// Format empty list as `<>`.
|
|
|
|
if (Left.is(tok::less) && Right.is(tok::greater))
|
|
|
|
return false;
|
|
|
|
return !Style.Cpp11BracedListStyle;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2018-02-06 19:34:34 +08:00
|
|
|
}
|
2013-07-01 17:47:25 +08:00
|
|
|
if (Right.is(tok::ellipsis))
|
2016-05-19 14:19:17 +08:00
|
|
|
return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous &&
|
|
|
|
Left.Previous->is(tok::kw_case));
|
2013-09-04 16:20:47 +08:00
|
|
|
if (Left.is(tok::l_square) && Right.is(tok::amp))
|
|
|
|
return false;
|
2017-08-14 19:06:07 +08:00
|
|
|
if (Right.is(TT_PointerOrReference)) {
|
|
|
|
if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) {
|
|
|
|
if (!Left.MatchingParen)
|
|
|
|
return true;
|
|
|
|
FormatToken *TokenBeforeMatchingParen =
|
|
|
|
Left.MatchingParen->getPreviousNonComment();
|
|
|
|
if (!TokenBeforeMatchingParen ||
|
|
|
|
!TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return (Left.Tok.isLiteral() ||
|
2015-02-25 18:30:06 +08:00
|
|
|
(!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
|
2015-03-02 02:55:26 +08:00
|
|
|
(Style.PointerAlignment != FormatStyle::PAS_Left ||
|
2016-10-05 04:18:25 +08:00
|
|
|
(Line.IsMultiVariableDeclStmt &&
|
|
|
|
(Left.NestingLevel == 0 ||
|
|
|
|
(Left.NestingLevel == 1 && Line.First->is(tok::kw_for)))))));
|
2017-08-14 19:06:07 +08:00
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
|
|
|
|
(!Left.is(TT_PointerOrReference) ||
|
2015-03-02 02:55:26 +08:00
|
|
|
(Style.PointerAlignment != FormatStyle::PAS_Right &&
|
|
|
|
!Line.IsMultiVariableDeclStmt)))
|
2013-05-08 22:58:20 +08:00
|
|
|
return true;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_PointerOrReference))
|
2017-01-09 19:04:07 +08:00
|
|
|
return Right.Tok.isLiteral() || Right.is(TT_BlockComment) ||
|
|
|
|
(Right.isOneOf(Keywords.kw_override, Keywords.kw_final) &&
|
|
|
|
!Right.is(TT_StartOfName)) ||
|
2015-06-12 17:59:16 +08:00
|
|
|
(Right.is(tok::l_brace) && Right.BlockKind == BK_Block) ||
|
2015-04-23 18:23:53 +08:00
|
|
|
(!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare,
|
|
|
|
tok::l_paren) &&
|
2015-03-02 02:55:26 +08:00
|
|
|
(Style.PointerAlignment != FormatStyle::PAS_Right &&
|
|
|
|
!Line.IsMultiVariableDeclStmt) &&
|
|
|
|
Left.Previous &&
|
2013-05-29 22:47:47 +08:00
|
|
|
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Right.is(tok::star) && Left.is(tok::l_paren))
|
|
|
|
return false;
|
2018-02-15 23:30:22 +08:00
|
|
|
const auto SpaceRequiredForArrayInitializerLSquare =
|
|
|
|
[](const FormatToken &LSquareTok, const FormatStyle &Style) {
|
|
|
|
return Style.SpacesInContainerLiterals ||
|
|
|
|
((Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) &&
|
|
|
|
!Style.Cpp11BracedListStyle &&
|
|
|
|
LSquareTok.endsSequence(tok::l_square, tok::colon,
|
|
|
|
TT_SelectorName));
|
|
|
|
};
|
2013-02-10 10:08:05 +08:00
|
|
|
if (Left.is(tok::l_square))
|
2018-02-15 23:30:22 +08:00
|
|
|
return (Left.is(TT_ArrayInitializerLSquare) && Right.isNot(tok::r_square) &&
|
|
|
|
SpaceRequiredForArrayInitializerLSquare(Left, Style)) ||
|
2017-09-07 22:28:32 +08:00
|
|
|
(Left.isOneOf(TT_ArraySubscriptLSquare,
|
|
|
|
TT_StructuredBindingLSquare) &&
|
|
|
|
Style.SpacesInSquareBrackets && Right.isNot(tok::r_square));
|
2013-02-10 10:08:05 +08:00
|
|
|
if (Right.is(tok::r_square))
|
2014-08-26 19:41:14 +08:00
|
|
|
return Right.MatchingParen &&
|
2018-02-15 23:30:22 +08:00
|
|
|
((Right.MatchingParen->is(TT_ArrayInitializerLSquare) &&
|
|
|
|
SpaceRequiredForArrayInitializerLSquare(*Right.MatchingParen,
|
|
|
|
Style)) ||
|
2014-08-26 19:41:14 +08:00
|
|
|
(Style.SpacesInSquareBrackets &&
|
2017-09-07 22:28:32 +08:00
|
|
|
Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare,
|
2018-03-12 23:42:38 +08:00
|
|
|
TT_StructuredBindingLSquare)) ||
|
|
|
|
Right.MatchingParen->is(TT_AttributeParen));
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(tok::l_square) &&
|
2017-06-19 22:41:21 +08:00
|
|
|
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
|
2017-09-07 22:28:32 +08:00
|
|
|
TT_DesignatedInitializerLSquare,
|
2018-03-12 23:42:38 +08:00
|
|
|
TT_StructuredBindingLSquare, TT_AttributeSquare) &&
|
2014-11-25 18:05:17 +08:00
|
|
|
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2014-08-26 17:37:52 +08:00
|
|
|
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
|
|
|
|
return !Left.Children.empty(); // No spaces in "{}".
|
|
|
|
if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
|
|
|
|
(Right.is(tok::r_brace) && Right.MatchingParen &&
|
|
|
|
Right.MatchingParen->BlockKind != BK_Block))
|
|
|
|
return !Style.Cpp11BracedListStyle;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_BlockComment))
|
2014-05-06 22:41:29 +08:00
|
|
|
return !Left.TokenText.endswith("=*/");
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Right.is(tok::l_paren)) {
|
2018-03-12 23:42:38 +08:00
|
|
|
if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
|
|
|
|
(Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
|
2013-07-18 04:25:02 +08:00
|
|
|
return true;
|
2014-11-27 22:55:17 +08:00
|
|
|
return Line.Type == LT_ObjCDecl || Left.is(tok::semi) ||
|
2013-12-10 18:18:34 +08:00
|
|
|
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
|
2015-08-14 20:44:06 +08:00
|
|
|
(Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while,
|
2015-10-07 23:09:08 +08:00
|
|
|
tok::kw_switch, tok::kw_case, TT_ForEachMacro,
|
|
|
|
TT_ObjCForIn) ||
|
2017-06-19 15:40:49 +08:00
|
|
|
Left.endsSequence(tok::kw_constexpr, tok::kw_if) ||
|
2015-02-04 23:26:27 +08:00
|
|
|
(Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
|
|
|
|
tok::kw_new, tok::kw_delete) &&
|
2015-05-04 17:22:29 +08:00
|
|
|
(!Left.Previous || Left.Previous->isNot(tok::period))))) ||
|
2013-12-10 18:18:34 +08:00
|
|
|
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
|
2015-06-17 21:08:06 +08:00
|
|
|
(Left.is(tok::identifier) || Left.isFunctionLikeKeyword() ||
|
|
|
|
Left.is(tok::r_paren)) &&
|
2013-12-10 18:18:34 +08:00
|
|
|
Line.Type != LT_PreprocessorDirective);
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
2013-05-29 22:47:47 +08:00
|
|
|
if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword)
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_UnaryOperator))
|
2013-05-24 02:05:18 +08:00
|
|
|
return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
|
2014-11-25 18:05:17 +08:00
|
|
|
(Left.isNot(tok::colon) || Left.isNot(TT_ObjCMethodExpr));
|
2014-06-02 18:57:55 +08:00
|
|
|
if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
|
|
|
|
tok::r_paren) ||
|
2014-05-07 15:59:03 +08:00
|
|
|
Left.isSimpleTypeSpecifier()) &&
|
2013-09-04 16:20:47 +08:00
|
|
|
Right.is(tok::l_brace) && Right.getNextNonComment() &&
|
|
|
|
Right.BlockKind != BK_Block)
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2013-05-28 19:30:49 +08:00
|
|
|
if (Left.is(tok::period) || Right.is(tok::period))
|
|
|
|
return false;
|
2013-09-10 21:41:43 +08:00
|
|
|
if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L")
|
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_TemplateCloser) && Left.MatchingParen &&
|
2014-10-21 19:13:31 +08:00
|
|
|
Left.MatchingParen->Previous &&
|
|
|
|
Left.MatchingParen->Previous->is(tok::period))
|
2017-09-28 01:57:50 +08:00
|
|
|
// A.<B<C<...>>>DoSomething();
|
2014-10-21 19:13:31 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square))
|
2014-11-19 07:48:01 +08:00
|
|
|
return false;
|
2018-04-03 22:07:09 +08:00
|
|
|
if (Left.is(tok::l_brace) && Left.endsSequence(TT_DictLiteral, tok::at))
|
|
|
|
// Objective-C dictionary literal -> no space after opening brace.
|
|
|
|
return false;
|
2018-03-27 23:01:17 +08:00
|
|
|
if (Right.is(tok::r_brace) && Right.MatchingParen &&
|
|
|
|
Right.MatchingParen->endsSequence(TT_DictLiteral, tok::at))
|
|
|
|
// Objective-C dictionary literal -> no space before closing brace.
|
|
|
|
return false;
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
|
2014-10-21 15:51:54 +08:00
|
|
|
const FormatToken &Right) {
|
|
|
|
const FormatToken &Left = *Right.Previous;
|
2015-06-25 16:38:46 +08:00
|
|
|
if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
|
|
|
|
return true; // Never ever merge two identifiers.
|
2017-03-31 21:30:24 +08:00
|
|
|
if (Style.isCpp()) {
|
2015-06-25 16:38:46 +08:00
|
|
|
if (Left.is(tok::kw_operator))
|
|
|
|
return Right.is(tok::coloncolon);
|
2018-06-14 16:01:09 +08:00
|
|
|
if (Right.is(tok::l_brace) && Right.BlockKind == BK_BracedInit &&
|
|
|
|
!Left.opensScope() && Style.SpaceBeforeCpp11BracedList)
|
|
|
|
return true;
|
2017-07-03 23:05:14 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) {
|
2014-10-21 15:51:54 +08:00
|
|
|
if (Right.is(tok::period) &&
|
2014-11-04 20:41:02 +08:00
|
|
|
Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
|
2015-11-20 22:32:54 +08:00
|
|
|
Keywords.kw_repeated, Keywords.kw_extend))
|
2014-10-21 15:51:54 +08:00
|
|
|
return true;
|
|
|
|
if (Right.is(tok::l_paren) &&
|
2014-11-04 20:41:02 +08:00
|
|
|
Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
|
2014-10-21 15:51:54 +08:00
|
|
|
return true;
|
2017-07-06 21:58:29 +08:00
|
|
|
if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName))
|
|
|
|
return true;
|
2018-02-13 18:20:39 +08:00
|
|
|
// 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;
|
2018-02-15 03:47:58 +08:00
|
|
|
// A percent is probably part of a formatting specification, such as %lld.
|
|
|
|
if (Left.is(tok::percent))
|
|
|
|
return false;
|
2018-04-05 17:33:03 +08:00
|
|
|
// 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.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin();
|
2014-10-21 15:51:54 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript) {
|
2016-03-17 20:17:59 +08:00
|
|
|
if (Left.is(TT_JsFatArrow))
|
|
|
|
return true;
|
2017-05-19 05:19:29 +08:00
|
|
|
// for await ( ...
|
2017-09-20 17:51:03 +08:00
|
|
|
if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous &&
|
|
|
|
Left.Previous->is(tok::kw_for))
|
2017-05-16 03:33:20 +08:00
|
|
|
return true;
|
2017-02-27 19:15:53 +08:00
|
|
|
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_JsFatArrow))
|
|
|
|
return true;
|
|
|
|
}
|
2016-08-25 18:13:21 +08:00
|
|
|
if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
|
|
|
|
(Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
|
|
|
|
return false;
|
2017-07-04 23:30:21 +08:00
|
|
|
// In tagged template literals ("html`bar baz`"), there is no space between
|
|
|
|
// the tag identifier and the template string. getIdentifierInfo makes sure
|
|
|
|
// that the identifier is not a pseudo keyword like `yield`, either.
|
|
|
|
if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
|
|
|
|
Right.is(TT_TemplateString))
|
2016-08-25 18:13:21 +08:00
|
|
|
return false;
|
2016-04-25 06:05:09 +08:00
|
|
|
if (Right.is(tok::star) &&
|
|
|
|
Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
|
|
|
|
return false;
|
2016-10-31 21:18:25 +08:00
|
|
|
if (Right.isOneOf(tok::l_brace, tok::l_square) &&
|
2017-08-01 23:46:10 +08:00
|
|
|
Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
|
|
|
|
Keywords.kw_extends, Keywords.kw_implements))
|
2016-10-31 21:18:25 +08:00
|
|
|
return true;
|
2017-08-15 00:08:16 +08:00
|
|
|
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;
|
|
|
|
}
|
2017-04-05 18:56:07 +08:00
|
|
|
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
|
2017-11-24 18:48:25 +08:00
|
|
|
// (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).
|
2017-04-05 18:56:07 +08:00
|
|
|
(Left.is(Keywords.kw_of) && Left.Previous &&
|
2018-02-19 20:32:13 +08:00
|
|
|
(Left.Previous->Tok.is(tok::identifier) ||
|
2017-11-24 18:48:25 +08:00
|
|
|
Left.Previous->isOneOf(tok::r_square, tok::r_brace)))) &&
|
2016-03-17 20:17:59 +08:00
|
|
|
(!Left.Previous || !Left.Previous->is(tok::period)))
|
2014-10-21 15:51:54 +08:00
|
|
|
return true;
|
2016-11-01 14:23:10 +08:00
|
|
|
if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous &&
|
2016-11-01 14:22:54 +08:00
|
|
|
Left.Previous->is(tok::period) && Right.is(tok::l_paren))
|
|
|
|
return false;
|
2016-08-22 22:23:30 +08:00
|
|
|
if (Left.is(Keywords.kw_as) &&
|
|
|
|
Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren))
|
|
|
|
return true;
|
2016-01-05 00:10:36 +08:00
|
|
|
if (Left.is(tok::kw_default) && Left.Previous &&
|
|
|
|
Left.Previous->is(tok::kw_export))
|
|
|
|
return true;
|
2015-12-30 16:00:58 +08:00
|
|
|
if (Left.is(Keywords.kw_is) && Right.is(tok::l_brace))
|
|
|
|
return true;
|
2015-04-13 23:01:40 +08:00
|
|
|
if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion))
|
2015-02-19 01:09:53 +08:00
|
|
|
return false;
|
2016-03-22 01:57:31 +08:00
|
|
|
if (Left.is(TT_JsTypeOperator) || Right.is(TT_JsTypeOperator))
|
|
|
|
return false;
|
2015-02-20 00:07:32 +08:00
|
|
|
if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
|
2015-02-20 00:14:18 +08:00
|
|
|
Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
|
2015-02-20 00:07:32 +08:00
|
|
|
return false;
|
2015-05-26 15:18:56 +08:00
|
|
|
if (Left.is(tok::ellipsis))
|
|
|
|
return false;
|
2015-03-15 21:59:51 +08:00
|
|
|
if (Left.is(TT_TemplateCloser) &&
|
2015-05-02 15:54:58 +08:00
|
|
|
!Right.isOneOf(tok::equal, tok::l_brace, tok::comma, tok::l_square,
|
2015-03-15 21:59:51 +08:00
|
|
|
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;
|
2017-03-13 17:14:23 +08:00
|
|
|
if (Right.is(TT_JsNonNullAssertion))
|
2016-06-13 08:49:54 +08:00
|
|
|
return false;
|
2017-11-25 01:04:40 +08:00
|
|
|
if (Left.is(TT_JsNonNullAssertion) &&
|
|
|
|
Right.isOneOf(Keywords.kw_as, Keywords.kw_in))
|
|
|
|
return true; // "x! as string", "x! in y"
|
2014-11-03 06:00:57 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Java) {
|
2014-11-24 04:54:37 +08:00
|
|
|
if (Left.is(tok::r_square) && Right.is(tok::l_brace))
|
|
|
|
return true;
|
2014-11-04 20:41:02 +08:00
|
|
|
if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren))
|
2014-11-03 06:00:57 +08:00
|
|
|
return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
|
2014-11-21 20:19:07 +08:00
|
|
|
if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private,
|
|
|
|
tok::kw_protected) ||
|
2015-01-14 06:32:50 +08:00
|
|
|
Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract,
|
|
|
|
Keywords.kw_native)) &&
|
2014-11-25 18:05:17 +08:00
|
|
|
Right.is(TT_TemplateOpener))
|
2014-11-03 10:35:14 +08:00
|
|
|
return true;
|
2014-10-21 15:51:54 +08:00
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_ImplicitStringLiteral))
|
2014-10-21 15:51:54 +08:00
|
|
|
return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
|
2013-01-30 05:01:14 +08:00
|
|
|
if (Line.Type == LT_ObjCMethodDecl) {
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_ObjCMethodSpecifier))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2018-04-28 02:51:12 +08:00
|
|
|
if (Left.is(tok::r_paren) && canBeObjCSelectorComponent(Right))
|
2018-03-22 11:23:53 +08:00
|
|
|
// 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.
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Line.Type == LT_ObjCProperty &&
|
2014-10-21 15:51:54 +08:00
|
|
|
(Right.is(tok::equal) || Left.is(tok::equal)))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
|
|
|
|
2015-06-05 21:18:09 +08:00
|
|
|
if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
|
|
|
|
Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow))
|
2013-07-09 22:36:48 +08:00
|
|
|
return true;
|
2016-01-09 23:56:40 +08:00
|
|
|
if (Right.is(TT_OverloadedOperatorLParen))
|
|
|
|
return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
|
2014-10-21 15:51:54 +08:00
|
|
|
if (Left.is(tok::comma))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2014-10-21 15:51:54 +08:00
|
|
|
if (Right.is(tok::comma))
|
2013-02-28 21:40:17 +08:00
|
|
|
return false;
|
[clang-format] Add SpaceBeforeColon option
Summary:
When disabled, this option allows removing the space before colon,
making it act more like the semi-colon. When enabled (default), the
current behavior is not affected.
This mostly affects C++11 loop, initializer list, inheritance list and
container literals:
class Foo: Bar {}
Foo::Foo(): a(a) {}
for (auto i: myList) {}
f({a: 1, b: 2, c: 3});
Reviewers: krasimir, djasper
Reviewed By: djasper
Subscribers: xvallspl, teemperor, karies, cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D32525
llvm-svn: 326426
2018-03-01 18:09:13 +08:00
|
|
|
if (Right.is(TT_ObjCBlockLParen))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
[clang-format] Add SpaceBeforeColon option
Summary:
When disabled, this option allows removing the space before colon,
making it act more like the semi-colon. When enabled (default), the
current behavior is not affected.
This mostly affects C++11 loop, initializer list, inheritance list and
container literals:
class Foo: Bar {}
Foo::Foo(): a(a) {}
for (auto i: myList) {}
f({a: 1, b: 2, c: 3});
Reviewers: krasimir, djasper
Reviewed By: djasper
Subscribers: xvallspl, teemperor, karies, cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D32525
llvm-svn: 326426
2018-03-01 18:09:13 +08:00
|
|
|
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;
|
2015-05-05 16:40:32 +08:00
|
|
|
if (Right.is(tok::colon)) {
|
|
|
|
if (Line.First->isOneOf(tok::kw_case, tok::kw_default) ||
|
2015-05-06 23:19:47 +08:00
|
|
|
!Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi))
|
2015-05-05 16:40:32 +08:00
|
|
|
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;
|
2018-03-12 23:42:38 +08:00
|
|
|
if (Right.is(TT_AttributeColon))
|
|
|
|
return false;
|
2015-05-05 16:40:32 +08:00
|
|
|
return true;
|
|
|
|
}
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_UnaryOperator))
|
|
|
|
return Right.is(TT_BinaryOperator);
|
2015-05-15 17:05:31 +08:00
|
|
|
|
|
|
|
// If the next token is a binary operator or a selector name, we have
|
|
|
|
// incorrectly classified the parenthesis as a cast. FIXME: Detect correctly.
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_CastRParen))
|
2015-05-15 17:05:31 +08:00
|
|
|
return Style.SpaceAfterCStyleCast ||
|
|
|
|
Right.isOneOf(TT_BinaryOperator, TT_SelectorName);
|
|
|
|
|
2018-02-06 19:34:34 +08:00
|
|
|
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;
|
2014-11-25 18:05:17 +08:00
|
|
|
return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
|
2013-10-29 22:52:02 +08:00
|
|
|
(Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
|
2018-02-06 19:34:34 +08:00
|
|
|
}
|
2017-06-19 22:41:21 +08:00
|
|
|
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)))
|
2013-02-28 21:40:17 +08:00
|
|
|
return false;
|
2013-09-25 23:15:02 +08:00
|
|
|
if (!Style.SpaceBeforeAssignmentOperators &&
|
2014-10-21 15:51:54 +08:00
|
|
|
Right.getPrecedence() == prec::Assignment)
|
2013-09-25 23:15:02 +08:00
|
|
|
return false;
|
2017-02-17 18:44:07 +08:00
|
|
|
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.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
|
2016-05-09 02:14:01 +08:00
|
|
|
if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment))
|
2014-11-25 18:05:17 +08:00
|
|
|
return (Left.is(TT_TemplateOpener) &&
|
2014-10-24 04:22:22 +08:00
|
|
|
Style.Standard == FormatStyle::LS_Cpp03) ||
|
2017-02-17 18:44:07 +08:00
|
|
|
!(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
|
2017-09-20 17:51:03 +08:00
|
|
|
tok::kw___super, TT_TemplateCloser,
|
2018-03-22 22:30:28 +08:00
|
|
|
TT_TemplateOpener)) ||
|
|
|
|
(Left.is(tok ::l_paren) && Style.SpacesInParentheses);
|
2014-11-25 18:05:17 +08:00
|
|
|
if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
|
2014-10-21 17:57:09 +08:00
|
|
|
return Style.SpacesInAngles;
|
2017-09-27 08:58:45 +08:00
|
|
|
// Space before TT_StructuredBindingLSquare.
|
|
|
|
if (Right.is(TT_StructuredBindingLSquare))
|
|
|
|
return !Left.isOneOf(tok::amp, tok::ampamp) ||
|
|
|
|
Style.PointerAlignment != 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 Style.PointerAlignment != FormatStyle::PAS_Left;
|
2014-11-25 18:05:17 +08:00
|
|
|
if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
|
2015-11-20 23:26:50 +08:00
|
|
|
(Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
|
|
|
|
!Right.is(tok::r_paren)))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2015-02-26 19:30:50 +08:00
|
|
|
if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) &&
|
|
|
|
Right.isNot(TT_FunctionTypeLParen))
|
2014-08-06 01:58:54 +08:00
|
|
|
return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) &&
|
|
|
|
Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen))
|
2014-10-20 21:56:30 +08:00
|
|
|
return false;
|
2014-10-21 15:51:54 +08:00
|
|
|
if (Right.is(tok::less) && Left.isNot(tok::l_paren) &&
|
2015-06-17 17:43:56 +08:00
|
|
|
Line.startsWith(tok::hash))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_TrailingUnaryOperator))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_RegexLiteral))
|
2014-05-08 15:01:45 +08:00
|
|
|
return false;
|
2014-10-21 15:51:54 +08:00
|
|
|
return spaceRequiredBetween(Line, Left, Right);
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
2014-06-02 18:17:32 +08:00
|
|
|
// 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.BlockKind == BK_Block &&
|
2014-11-25 18:05:17 +08:00
|
|
|
!Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral);
|
2014-06-02 18:17:32 +08:00
|
|
|
}
|
|
|
|
|
2013-09-17 17:52:48 +08:00
|
|
|
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
|
|
|
|
const FormatToken &Right) {
|
2014-03-21 20:38:57 +08:00
|
|
|
const FormatToken &Left = *Right.Previous;
|
2015-07-28 23:50:24 +08:00
|
|
|
if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0)
|
2014-06-04 20:40:57 +08:00
|
|
|
return true;
|
2014-11-12 03:34:57 +08:00
|
|
|
|
2015-06-17 17:44:07 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
// FIXME: This might apply to other languages and token kinds.
|
2016-03-03 06:44:03 +08:00
|
|
|
if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous &&
|
|
|
|
Left.Previous->is(tok::string_literal))
|
2015-06-17 17:44:07 +08:00
|
|
|
return true;
|
2015-06-17 21:08:06 +08:00
|
|
|
if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) && Line.Level == 0 &&
|
|
|
|
Left.Previous && Left.Previous->is(tok::equal) &&
|
|
|
|
Line.First->isOneOf(tok::identifier, Keywords.kw_import, tok::kw_export,
|
|
|
|
tok::kw_const) &&
|
2015-09-28 22:28:08 +08:00
|
|
|
// kw_var/kw_let are pseudo-tokens that are tok::identifier, so match
|
|
|
|
// above.
|
|
|
|
!Line.First->isOneOf(Keywords.kw_var, Keywords.kw_let))
|
2015-06-17 17:44:07 +08:00
|
|
|
// Object literals on the top level of a file are treated as "enum-style".
|
|
|
|
// Each key/value pair is put on a separate line, instead of bin-packing.
|
|
|
|
return true;
|
|
|
|
if (Left.is(tok::l_brace) && Line.Level == 0 &&
|
|
|
|
(Line.startsWith(tok::kw_enum) ||
|
2017-08-02 01:12:15 +08:00
|
|
|
Line.startsWith(tok::kw_const, tok::kw_enum) ||
|
|
|
|
Line.startsWith(tok::kw_export, tok::kw_enum) ||
|
|
|
|
Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum)))
|
2015-06-17 17:44:07 +08:00
|
|
|
// JavaScript top-level enum key/value pairs are put on separate lines
|
|
|
|
// instead of bin-packing.
|
|
|
|
return true;
|
|
|
|
if (Right.is(tok::r_brace) && Left.is(tok::l_brace) &&
|
|
|
|
!Left.Children.empty())
|
|
|
|
// Support AllowShortFunctionsOnASingleLine for JavaScript.
|
|
|
|
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
|
2015-11-21 00:44:28 +08:00
|
|
|
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty ||
|
2015-06-17 17:44:07 +08:00
|
|
|
(Left.NestingLevel == 0 && Line.Level == 0 &&
|
2017-06-21 21:56:02 +08:00
|
|
|
Style.AllowShortFunctionsOnASingleLine &
|
|
|
|
FormatStyle::SFS_InlineOnly);
|
2015-06-17 17:44:07 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Java) {
|
|
|
|
if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
|
|
|
|
Right.Next->is(tok::string_literal))
|
|
|
|
return true;
|
2017-01-31 20:07:35 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Cpp ||
|
2017-02-03 16:29:02 +08:00
|
|
|
Style.Language == FormatStyle::LK_ObjC ||
|
2018-03-08 05:30:38 +08:00
|
|
|
Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) {
|
2017-04-11 17:55:00 +08:00
|
|
|
if (Left.isStringLiteral() && Right.isStringLiteral())
|
2017-01-31 20:07:35 +08:00
|
|
|
return true;
|
2015-06-17 17:44:07 +08:00
|
|
|
}
|
|
|
|
|
2017-05-15 19:15:29 +08:00
|
|
|
// If the last token before a '}', ']', or ')' is a comma or a trailing
|
|
|
|
// comment, the intention is to insert a line break after it in order to make
|
2017-05-18 16:07:52 +08:00
|
|
|
// shuffling around entries easier. Import statements, especially in
|
|
|
|
// JavaScript, can be an exception to this rule.
|
|
|
|
if (Style.JavaScriptWrapImports || Line.Type != LT_ImportStatement) {
|
|
|
|
const FormatToken *BeforeClosingBrace = nullptr;
|
|
|
|
if ((Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
|
|
|
|
(Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
Left.is(tok::l_paren))) &&
|
|
|
|
Left.BlockKind != BK_Block && Left.MatchingParen)
|
|
|
|
BeforeClosingBrace = Left.MatchingParen->Previous;
|
|
|
|
else if (Right.MatchingParen &&
|
|
|
|
(Right.MatchingParen->isOneOf(tok::l_brace,
|
|
|
|
TT_ArrayInitializerLSquare) ||
|
|
|
|
(Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
Right.MatchingParen->is(tok::l_paren))))
|
|
|
|
BeforeClosingBrace = &Left;
|
|
|
|
if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
|
|
|
|
BeforeClosingBrace->isTrailingComment()))
|
|
|
|
return true;
|
|
|
|
}
|
2014-11-12 03:34:57 +08:00
|
|
|
|
2015-01-08 21:56:57 +08:00
|
|
|
if (Right.is(tok::comment))
|
2014-11-12 03:34:57 +08:00
|
|
|
return Left.BlockKind != BK_BracedInit &&
|
2014-11-25 18:05:17 +08:00
|
|
|
Left.isNot(TT_CtorInitializerColon) &&
|
2014-04-11 20:27:47 +08:00
|
|
|
(Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
|
2015-05-11 23:15:48 +08:00
|
|
|
if (Left.isTrailingComment())
|
2015-06-17 21:08:06 +08:00
|
|
|
return true;
|
2015-01-08 21:56:57 +08:00
|
|
|
if (Right.Previous->IsUnterminatedLiteral)
|
2013-09-17 17:52:48 +08:00
|
|
|
return true;
|
2015-01-08 21:56:57 +08:00
|
|
|
if (Right.is(tok::lessless) && Right.Next &&
|
|
|
|
Right.Previous->is(tok::string_literal) &&
|
|
|
|
Right.Next->is(tok::string_literal))
|
2013-09-17 17:52:48 +08:00
|
|
|
return true;
|
2015-01-08 21:56:57 +08:00
|
|
|
if (Right.Previous->ClosesTemplateDeclaration &&
|
|
|
|
Right.Previous->MatchingParen &&
|
|
|
|
Right.Previous->MatchingParen->NestingLevel == 0 &&
|
2018-05-16 16:25:03 +08:00
|
|
|
Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes)
|
2013-09-17 17:52:48 +08:00
|
|
|
return true;
|
2017-05-24 19:36:58 +08:00
|
|
|
if (Right.is(TT_CtorInitializerComma) &&
|
|
|
|
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
|
|
|
|
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
|
|
|
return true;
|
|
|
|
if (Right.is(TT_CtorInitializerColon) &&
|
|
|
|
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
|
2015-01-08 21:56:57 +08:00
|
|
|
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
2013-09-17 17:52:48 +08:00
|
|
|
return true;
|
2017-03-10 23:10:37 +08:00
|
|
|
// Break only if we have multiple inheritance.
|
2018-06-11 22:41:26 +08:00
|
|
|
if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma &&
|
|
|
|
Right.is(TT_InheritanceComma))
|
2017-09-20 17:51:03 +08:00
|
|
|
return true;
|
2015-01-08 21:56:57 +08:00
|
|
|
if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\""))
|
2018-03-22 22:43:54 +08:00
|
|
|
// Multiline raw string literals are special wrt. line breaks. The author
|
|
|
|
// has made a deliberate choice and might have aligned the contents of the
|
|
|
|
// string literal accordingly. Thus, we try keep existing line breaks.
|
|
|
|
return Right.IsMultiline && Right.NewlinesBefore > 0;
|
2017-06-27 21:43:07 +08:00
|
|
|
if ((Right.Previous->is(tok::l_brace) ||
|
2017-09-20 17:51:03 +08:00
|
|
|
(Right.Previous->is(tok::less) && Right.Previous->Previous &&
|
|
|
|
Right.Previous->Previous->is(tok::equal))) &&
|
2017-06-27 21:43:07 +08:00
|
|
|
Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
|
|
|
|
// Don't put enums or option definitions onto single lines in protocol
|
|
|
|
// buffers.
|
2014-01-19 17:04:08 +08:00
|
|
|
return true;
|
2017-06-27 21:43:07 +08:00
|
|
|
}
|
2015-05-10 16:42:04 +08:00
|
|
|
if (Right.is(TT_InlineASMBrace))
|
|
|
|
return Right.HasUnescapedNewline;
|
2015-01-08 21:56:57 +08:00
|
|
|
if (isAllmanBrace(Left) || isAllmanBrace(Right))
|
2015-09-29 22:57:55 +08:00
|
|
|
return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) ||
|
2017-09-20 17:51:03 +08:00
|
|
|
(Line.startsWith(tok::kw_typedef, tok::kw_enum) &&
|
|
|
|
Style.BraceWrapping.AfterEnum) ||
|
2015-09-29 22:57:55 +08:00
|
|
|
(Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) ||
|
|
|
|
(Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct);
|
2015-01-08 21:56:57 +08:00
|
|
|
if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine)
|
|
|
|
return true;
|
2014-04-09 17:53:23 +08:00
|
|
|
|
2015-02-20 00:07:32 +08:00
|
|
|
if ((Style.Language == FormatStyle::LK_Java ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript) &&
|
|
|
|
Left.is(TT_LeadingJavaAnnotation) &&
|
|
|
|
Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) &&
|
2015-10-16 00:03:01 +08:00
|
|
|
(Line.Last->is(tok::l_brace) || Style.BreakAfterJavaFieldAnnotations))
|
2015-02-20 00:07:32 +08:00
|
|
|
return true;
|
|
|
|
|
2018-02-13 18:20:39 +08:00
|
|
|
if (Right.is(TT_ProtoExtensionLSquare))
|
|
|
|
return true;
|
|
|
|
|
2018-06-11 20:53:25 +08:00
|
|
|
// In text proto instances if a submessage contains at least 2 entries and at
|
|
|
|
// least one of them is a submessage, like A { ... B { ... } ... },
|
|
|
|
// put all of the entries of A on separate lines by forcing the selector of
|
|
|
|
// the submessage B to be put on a newline.
|
|
|
|
//
|
|
|
|
// Example: these can stay on one line:
|
|
|
|
// a { scalar_1: 1 scalar_2: 2 }
|
|
|
|
// a { b { key: value } }
|
|
|
|
//
|
|
|
|
// and these entries need to be on a new line even if putting them all in one
|
|
|
|
// line is under the column limit:
|
|
|
|
// a {
|
|
|
|
// scalar: 1
|
|
|
|
// b { key: value }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// We enforce this by breaking before a submessage field that has previous
|
|
|
|
// siblings, *and* breaking before a field that follows a submessage field.
|
|
|
|
//
|
|
|
|
// Be careful to exclude the case [proto.ext] { ... } since the `]` is
|
|
|
|
// the TT_SelectorName there, but we don't want to break inside the brackets.
|
2018-06-25 20:43:12 +08:00
|
|
|
//
|
|
|
|
// Another edge case is @submessage { key: value }, which is a common
|
|
|
|
// substitution placeholder. In this case we want to keep `@` and `submessage`
|
|
|
|
// together.
|
|
|
|
//
|
2018-06-11 20:53:25 +08:00
|
|
|
// We ensure elsewhere that extensions are always on their own line.
|
|
|
|
if ((Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) &&
|
|
|
|
Right.is(TT_SelectorName) && !Right.is(tok::r_square) && Right.Next) {
|
2018-06-25 20:43:12 +08:00
|
|
|
// Keep `@submessage` together in:
|
|
|
|
// @submessage { key: value }
|
|
|
|
if (Right.Previous && Right.Previous->is(tok::at))
|
|
|
|
return false;
|
2018-06-11 20:53:25 +08:00
|
|
|
// Look for the scope opener after selector in cases like:
|
|
|
|
// selector { ...
|
|
|
|
// selector: { ...
|
2018-06-25 20:43:12 +08:00
|
|
|
// selector: @base { ...
|
|
|
|
FormatToken *LBrace = Right.Next;
|
|
|
|
if (LBrace && LBrace->is(tok::colon)) {
|
|
|
|
LBrace = LBrace->Next;
|
|
|
|
if (LBrace && LBrace->is(tok::at)) {
|
|
|
|
LBrace = LBrace->Next;
|
|
|
|
if (LBrace)
|
|
|
|
LBrace = LBrace->Next;
|
|
|
|
}
|
|
|
|
}
|
2018-06-11 20:53:25 +08:00
|
|
|
if (LBrace &&
|
|
|
|
// The scope opener is one of {, [, <:
|
|
|
|
// selector { ... }
|
|
|
|
// selector [ ... ]
|
|
|
|
// selector < ... >
|
|
|
|
//
|
|
|
|
// In case of selector { ... }, the l_brace is TT_DictLiteral.
|
|
|
|
// In case of an empty selector {}, the l_brace is not TT_DictLiteral,
|
|
|
|
// so we check for immediately following r_brace.
|
|
|
|
((LBrace->is(tok::l_brace) &&
|
|
|
|
(LBrace->is(TT_DictLiteral) ||
|
|
|
|
(LBrace->Next && LBrace->Next->is(tok::r_brace)))) ||
|
|
|
|
LBrace->is(TT_ArrayInitializerLSquare) || LBrace->is(tok::less))) {
|
|
|
|
// If Left.ParameterCount is 0, then this submessage entry is not the
|
|
|
|
// first in its parent submessage, and we want to break before this entry.
|
|
|
|
// If Left.ParameterCount is greater than 0, then its parent submessage
|
|
|
|
// might contain 1 or more entries and we want to break before this entry
|
|
|
|
// if it contains at least 2 entries. We deal with this case later by
|
|
|
|
// detecting and breaking before the next entry in the parent submessage.
|
|
|
|
if (Left.ParameterCount == 0)
|
|
|
|
return true;
|
|
|
|
// However, if this submessage is the first entry in its parent
|
|
|
|
// submessage, Left.ParameterCount might be 1 in some cases.
|
|
|
|
// We deal with this case later by detecting an entry
|
|
|
|
// following a closing paren of this submessage.
|
|
|
|
}
|
2018-06-12 00:20:13 +08:00
|
|
|
|
2018-06-11 20:53:25 +08:00
|
|
|
// If this is an entry immediately following a submessage, it will be
|
|
|
|
// preceded by a closing paren of that submessage, like in:
|
|
|
|
// left---. .---right
|
|
|
|
// v v
|
|
|
|
// sub: { ... } key: value
|
|
|
|
// If there was a comment between `}` an `key` above, then `key` would be
|
|
|
|
// put on a new line anyways.
|
|
|
|
if (Left.isOneOf(tok::r_brace, tok::greater, tok::r_square))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-17 17:52:48 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-06 22:22:40 +08:00
|
|
|
bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
|
2013-05-29 22:47:47 +08:00
|
|
|
const FormatToken &Right) {
|
|
|
|
const FormatToken &Left = *Right.Previous;
|
2014-10-17 21:36:14 +08:00
|
|
|
|
2015-06-09 19:39:22 +08:00
|
|
|
// Language-specific stuff.
|
2014-10-17 21:36:14 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Java) {
|
2014-11-04 20:41:02 +08:00
|
|
|
if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
|
|
|
|
Keywords.kw_implements))
|
2014-10-17 21:36:14 +08:00
|
|
|
return false;
|
2014-11-04 20:41:02 +08:00
|
|
|
if (Right.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
|
|
|
|
Keywords.kw_implements))
|
2014-11-04 18:53:14 +08:00
|
|
|
return true;
|
2015-06-09 19:39:22 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_JavaScript) {
|
2016-09-07 02:39:30 +08:00
|
|
|
const FormatToken *NonComment = Right.getPreviousNonComment();
|
2017-03-13 15:10:18 +08:00
|
|
|
if (NonComment &&
|
2017-11-30 18:25:17 +08:00
|
|
|
NonComment->isOneOf(
|
|
|
|
tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break,
|
|
|
|
tok::kw_throw, Keywords.kw_interface, Keywords.kw_type,
|
|
|
|
tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected,
|
|
|
|
Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get,
|
|
|
|
Keywords.kw_set, Keywords.kw_async, Keywords.kw_await))
|
2017-05-22 22:58:26 +08:00
|
|
|
return false; // Otherwise automatic semicolon insertion would trigger.
|
2018-01-26 23:07:49 +08:00
|
|
|
if (Right.NestingLevel == 0 &&
|
|
|
|
(Left.Tok.getIdentifierInfo() ||
|
|
|
|
Left.isOneOf(tok::r_square, tok::r_paren)) &&
|
|
|
|
Right.isOneOf(tok::l_square, tok::l_paren))
|
|
|
|
return false; // Otherwise automatic semicolon insertion would trigger.
|
2015-06-09 19:39:22 +08:00
|
|
|
if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace))
|
|
|
|
return false;
|
2015-07-03 18:37:23 +08:00
|
|
|
if (Left.is(TT_JsTypeColon))
|
|
|
|
return true;
|
2018-06-12 00:20:13 +08:00
|
|
|
// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
|
|
|
|
if (Left.is(tok::exclaim) && Right.is(tok::colon))
|
|
|
|
return false;
|
2018-05-22 18:39:07 +08:00
|
|
|
if (Right.is(Keywords.kw_is))
|
2015-12-30 16:00:58 +08:00
|
|
|
return false;
|
2016-02-01 19:20:47 +08:00
|
|
|
if (Left.is(Keywords.kw_in))
|
|
|
|
return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None;
|
|
|
|
if (Right.is(Keywords.kw_in))
|
|
|
|
return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
|
2016-06-22 22:35:14 +08:00
|
|
|
if (Right.is(Keywords.kw_as))
|
|
|
|
return false; // must not break before as in 'x as type' casts
|
2017-03-02 03:26:12 +08:00
|
|
|
if (Left.is(Keywords.kw_as))
|
|
|
|
return true;
|
2017-03-13 17:14:23 +08:00
|
|
|
if (Left.is(TT_JsNonNullAssertion))
|
|
|
|
return true;
|
2016-11-11 00:20:58 +08:00
|
|
|
if (Left.is(Keywords.kw_declare) &&
|
|
|
|
Right.isOneOf(Keywords.kw_module, tok::kw_namespace,
|
|
|
|
Keywords.kw_function, tok::kw_class, tok::kw_enum,
|
|
|
|
Keywords.kw_interface, Keywords.kw_type, Keywords.kw_var,
|
|
|
|
Keywords.kw_let, tok::kw_const))
|
|
|
|
// See grammar for 'declare' statements at:
|
|
|
|
// https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#A.10
|
|
|
|
return false;
|
|
|
|
if (Left.isOneOf(Keywords.kw_module, tok::kw_namespace) &&
|
2017-02-20 22:51:16 +08:00
|
|
|
Right.isOneOf(tok::identifier, tok::string_literal))
|
2016-11-11 00:20:58 +08:00
|
|
|
return false; // must not break in "module foo { ...}"
|
2017-02-20 22:51:16 +08:00
|
|
|
if (Right.is(TT_TemplateString) && Right.closesScope())
|
|
|
|
return false;
|
|
|
|
if (Left.is(TT_TemplateString) && Left.opensScope())
|
|
|
|
return true;
|
2014-10-17 21:36:14 +08:00
|
|
|
}
|
|
|
|
|
2013-11-23 22:27:27 +08:00
|
|
|
if (Left.is(tok::at))
|
|
|
|
return false;
|
2014-04-28 15:34:48 +08:00
|
|
|
if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
|
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation))
|
2015-01-14 17:51:32 +08:00
|
|
|
return !Right.is(tok::l_paren);
|
2015-03-12 23:04:53 +08:00
|
|
|
if (Right.is(TT_PointerOrReference))
|
|
|
|
return Line.IsMultiVariableDeclStmt ||
|
|
|
|
(Style.PointerAlignment == FormatStyle::PAS_Right &&
|
|
|
|
(!Right.Next || Right.Next->isNot(TT_FunctionDeclarationName)));
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
|
|
|
|
Right.is(tok::kw_operator))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2015-03-19 17:40:16 +08:00
|
|
|
if (Left.is(TT_PointerOrReference))
|
|
|
|
return false;
|
2013-11-08 08:57:11 +08:00
|
|
|
if (Right.isTrailingComment())
|
|
|
|
// We rely on MustBreakBefore being set correctly here as we should not
|
|
|
|
// change the "binding" behavior of a comment.
|
2013-12-20 05:41:37 +08:00
|
|
|
// The first comment in a braced lists is always interpreted as belonging to
|
|
|
|
// the first list element. Otherwise, it should be placed outside of the
|
|
|
|
// list.
|
2017-05-24 19:36:58 +08:00
|
|
|
return Left.BlockKind == BK_BracedInit ||
|
|
|
|
(Left.is(TT_CtorInitializerColon) &&
|
2017-09-20 17:51:03 +08:00
|
|
|
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon);
|
2013-11-08 08:57:11 +08:00
|
|
|
if (Left.is(tok::question) && Right.is(tok::colon))
|
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_ConditionalExpr) || Right.is(tok::question))
|
2013-11-08 08:57:11 +08:00
|
|
|
return Style.BreakBeforeTernaryOperators;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_ConditionalExpr) || Left.is(tok::question))
|
2013-11-08 08:57:11 +08:00
|
|
|
return !Style.BreakBeforeTernaryOperators;
|
2018-06-11 22:41:26 +08:00
|
|
|
if (Left.is(TT_InheritanceColon))
|
|
|
|
return Style.BreakInheritanceList == FormatStyle::BILS_AfterColon;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_InheritanceColon))
|
2018-06-11 22:41:26 +08:00
|
|
|
return Style.BreakInheritanceList != FormatStyle::BILS_AfterColon;
|
2016-11-12 15:38:22 +08:00
|
|
|
if (Right.is(TT_ObjCMethodExpr) && !Right.is(tok::r_square) &&
|
|
|
|
Left.isNot(TT_SelectorName))
|
|
|
|
return true;
|
2018-02-08 18:47:12 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(tok::colon) &&
|
|
|
|
!Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon))
|
2014-05-28 18:09:11 +08:00
|
|
|
return false;
|
2018-02-08 18:47:12 +08:00
|
|
|
if (Left.is(tok::colon) && Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) {
|
2018-06-13 01:26:31 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Proto ||
|
|
|
|
Style.Language == FormatStyle::LK_TextProto) {
|
|
|
|
if (!Style.AlwaysBreakBeforeMultilineStrings && Right.isStringLiteral())
|
|
|
|
return false;
|
|
|
|
// Prevent cases like:
|
|
|
|
//
|
|
|
|
// submessage:
|
|
|
|
// { key: valueeeeeeeeeeee }
|
|
|
|
//
|
|
|
|
// when the snippet does not fit into one line.
|
|
|
|
// Prefer:
|
|
|
|
//
|
|
|
|
// submessage: {
|
|
|
|
// key: valueeeeeeeeeeee
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// instead, even if it is longer by one line.
|
|
|
|
//
|
|
|
|
// Note that this allows allows the "{" to go over the column limit
|
|
|
|
// when the column limit is just between ":" and "{", but that does
|
|
|
|
// not happen too often and alternative formattings in this case are
|
|
|
|
// not much better.
|
|
|
|
//
|
|
|
|
// The code covers the cases:
|
|
|
|
//
|
|
|
|
// submessage: { ... }
|
|
|
|
// submessage: < ... >
|
|
|
|
// repeated: [ ... ]
|
|
|
|
if (((Right.is(tok::l_brace) || Right.is(tok::less)) &&
|
|
|
|
Right.is(TT_DictLiteral)) ||
|
|
|
|
Right.is(TT_ArrayInitializerLSquare))
|
|
|
|
return false;
|
|
|
|
}
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2018-02-08 18:47:12 +08:00
|
|
|
}
|
2018-03-16 23:23:22 +08:00
|
|
|
if (Right.is(tok::r_square) && Right.MatchingParen &&
|
|
|
|
Right.MatchingParen->is(TT_ProtoExtensionLSquare))
|
|
|
|
return false;
|
2015-05-13 18:23:03 +08:00
|
|
|
if (Right.is(TT_SelectorName) || (Right.is(tok::identifier) && Right.Next &&
|
|
|
|
Right.Next->is(TT_ObjCMethodExpr)))
|
2015-05-19 19:06:33 +08:00
|
|
|
return Left.isNot(tok::period); // FIXME: Properly parse ObjC calls.
|
2013-08-01 21:46:58 +08:00
|
|
|
if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty)
|
|
|
|
return true;
|
2015-08-24 23:10:01 +08:00
|
|
|
if (Left.ClosesTemplateDeclaration || Left.is(TT_FunctionAnnotationRParen))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.isOneOf(TT_RangeBasedForLoopColon, TT_OverloadedOperatorLParen,
|
|
|
|
TT_OverloadedOperator))
|
2013-02-14 16:42:54 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_RangeBasedForLoopColon))
|
2013-01-30 05:01:14 +08:00
|
|
|
return true;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_RangeBasedForLoopColon))
|
Allow breaking between type and name in for loops.
This fixes llvm.org/PR15033.
Also: Always break before a parameter, if the previous parameter was
split over multiple lines. This was necessary to make the right
decisions in for-loops, almost always makes the code more readable and
also fixes llvm.org/PR14873.
Before:
for (llvm::ArrayRef<NamedDecl *>::iterator I = FD->getDeclsInPrototypeScope()
.begin(), E = FD->getDeclsInPrototypeScope().end();
I != E; ++I) {
}
foo(bar(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
ccccccccccccccccccccccccccccc), d, bar(e, f));
After:
for (llvm::ArrayRef<NamedDecl *>::iterator
I = FD->getDeclsInPrototypeScope().begin(),
E = FD->getDeclsInPrototypeScope().end();
I != E; ++I) {
}
foo(bar(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
ccccccccccccccccccccccccccccc),
d, bar(e, f));
llvm-svn: 175741
2013-02-21 23:00:29 +08:00
|
|
|
return false;
|
2016-11-06 01:43:16 +08:00
|
|
|
if (Left.is(TT_TemplateCloser) && Right.is(TT_TemplateOpener))
|
|
|
|
return true;
|
2015-03-12 23:04:53 +08:00
|
|
|
if (Left.isOneOf(TT_TemplateCloser, TT_UnaryOperator) ||
|
2014-11-25 18:05:17 +08:00
|
|
|
Left.is(tok::kw_operator))
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
2015-04-23 20:59:09 +08:00
|
|
|
if (Left.is(tok::equal) && !Right.isOneOf(tok::kw_default, tok::kw_delete) &&
|
2015-08-21 19:44:57 +08:00
|
|
|
Line.Type == LT_VirtualFunctionDecl && Left.NestingLevel == 0)
|
2013-01-30 05:01:14 +08:00
|
|
|
return false;
|
clang-format: tweak formatting of variable initialization blocks
Summary:
This patch changes the behavior of PenaltyBreakBeforeFirstCallParameter
so that is does not apply after a brace, when Cpp11BracedListStyle is
false.
This way, variable initialization is wrapped more like an initializer
than like a function call, which is more consistent with user
expectations for this braced list style.
With PenaltyBreakBeforeFirstCallParameter=200, this gives the following
code: (with Cpp11BracedListStyle=false)
Before :
const std::unordered_map<std::string, int> Something::MyHashTable =
{ { "aaaaaaaaaaaaaaaaaaaaa", 0 },
{ "bbbbbbbbbbbbbbbbbbbbb", 1 },
{ "ccccccccccccccccccccc", 2 } };
After :
const std::unordered_set<std::string> Something::MyUnorderedSet = {
{ "aaaaaaaaaaaaaaaaaaaaa", 0 },
{ "bbbbbbbbbbbbbbbbbbbbb", 1 },
{ "ccccccccccccccccccccc", 2 }
};
Reviewers: krasimir, djasper, klimek
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D43290
llvm-svn: 332434
2018-05-16 16:03:52 +08:00
|
|
|
if (Left.is(tok::equal) && Right.is(tok::l_brace) &&
|
|
|
|
!Style.Cpp11BracedListStyle)
|
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(tok::l_paren) && Left.is(TT_AttributeParen))
|
2014-01-29 04:13:43 +08:00
|
|
|
return false;
|
|
|
|
if (Left.is(tok::l_paren) && Left.Previous &&
|
2015-02-26 17:49:08 +08:00
|
|
|
(Left.Previous->isOneOf(TT_BinaryOperator, TT_CastRParen)))
|
2014-01-29 04:13:43 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_ImplicitStringLiteral))
|
2013-10-30 21:54:53 +08:00
|
|
|
return false;
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser))
|
2013-09-05 17:29:45 +08:00
|
|
|
return false;
|
2015-07-07 21:50:50 +08:00
|
|
|
if (Right.is(tok::r_square) && Right.MatchingParen &&
|
|
|
|
Right.MatchingParen->is(TT_LambdaLSquare))
|
|
|
|
return false;
|
2013-09-05 17:29:45 +08:00
|
|
|
|
2013-05-22 16:28:26 +08:00
|
|
|
// We only break before r_brace if there was a corresponding break before
|
|
|
|
// the l_brace, which is tracked by BreakBeforeClosingBrace.
|
2013-09-05 17:29:45 +08:00
|
|
|
if (Right.is(tok::r_brace))
|
|
|
|
return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block;
|
2013-05-22 16:28:26 +08:00
|
|
|
|
2014-04-09 18:29:11 +08:00
|
|
|
// Allow breaking after a trailing annotation, e.g. after a method
|
|
|
|
// declaration.
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_TrailingAnnotation))
|
2014-04-09 18:29:11 +08:00
|
|
|
return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
|
|
|
|
tok::less, tok::coloncolon);
|
2013-01-30 05:01:14 +08:00
|
|
|
|
2018-03-12 23:42:38 +08:00
|
|
|
if (Right.is(tok::kw___attribute) ||
|
|
|
|
(Right.is(tok::l_square) && Right.is(TT_AttributeSquare)))
|
2013-03-14 17:50:46 +08:00
|
|
|
return true;
|
|
|
|
|
2013-02-23 15:46:38 +08:00
|
|
|
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
|
|
|
|
return true;
|
2013-07-27 00:56:36 +08:00
|
|
|
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
|
2014-04-15 17:54:30 +08:00
|
|
|
return true;
|
|
|
|
|
2017-05-24 19:36:58 +08:00
|
|
|
if (Left.is(TT_CtorInitializerColon))
|
|
|
|
return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
|
|
|
|
if (Right.is(TT_CtorInitializerColon))
|
|
|
|
return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_CtorInitializerComma) &&
|
2017-05-24 19:36:58 +08:00
|
|
|
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
|
2013-07-27 00:56:36 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_CtorInitializerComma) &&
|
2017-05-24 19:36:58 +08:00
|
|
|
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
|
2013-10-08 13:11:18 +08:00
|
|
|
return true;
|
2018-06-11 22:41:26 +08:00
|
|
|
if (Left.is(TT_InheritanceComma) &&
|
|
|
|
Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma)
|
2017-03-10 23:10:37 +08:00
|
|
|
return false;
|
2018-06-11 22:41:26 +08:00
|
|
|
if (Right.is(TT_InheritanceComma) &&
|
|
|
|
Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma)
|
2017-03-10 23:10:37 +08:00
|
|
|
return true;
|
2015-02-19 07:48:37 +08:00
|
|
|
if ((Left.is(tok::greater) && Right.is(tok::greater)) ||
|
|
|
|
(Left.is(tok::less) && Right.is(tok::less)))
|
2013-09-17 16:15:46 +08:00
|
|
|
return false;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Right.is(TT_BinaryOperator) &&
|
2014-09-15 19:11:00 +08:00
|
|
|
Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None &&
|
|
|
|
(Style.BreakBeforeBinaryOperators == FormatStyle::BOS_All ||
|
|
|
|
Right.getPrecedence() != prec::Assignment))
|
2014-05-13 16:01:47 +08:00
|
|
|
return true;
|
2014-11-25 18:05:17 +08:00
|
|
|
if (Left.is(TT_ArrayInitializerLSquare))
|
2013-10-22 23:30:28 +08:00
|
|
|
return true;
|
2014-08-12 21:22:26 +08:00
|
|
|
if (Right.is(tok::kw_typename) && Left.isNot(tok::kw_const))
|
|
|
|
return true;
|
2015-07-03 18:12:53 +08:00
|
|
|
if ((Left.isBinaryOperator() || Left.is(TT_BinaryOperator)) &&
|
|
|
|
!Left.isOneOf(tok::arrowstar, tok::lessless) &&
|
2014-09-15 19:11:00 +08:00
|
|
|
Style.BreakBeforeBinaryOperators != FormatStyle::BOS_All &&
|
|
|
|
(Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None ||
|
|
|
|
Left.getPrecedence() == prec::Assignment))
|
|
|
|
return true;
|
2018-03-12 23:42:38 +08:00
|
|
|
if ((Left.is(TT_AttributeSquare) && Right.is(tok::l_square)) ||
|
|
|
|
(Left.is(tok::r_square) && Right.is(TT_AttributeSquare)))
|
|
|
|
return false;
|
2014-09-15 19:11:00 +08:00
|
|
|
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
|
2016-05-27 16:59:34 +08:00
|
|
|
tok::kw_class, tok::kw_struct, tok::comment) ||
|
2015-03-27 02:46:28 +08:00
|
|
|
Right.isMemberAccess() ||
|
|
|
|
Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow, tok::lessless,
|
|
|
|
tok::colon, tok::l_square, tok::at) ||
|
2013-07-05 15:58:34 +08:00
|
|
|
(Left.is(tok::r_paren) &&
|
2014-01-29 04:13:43 +08:00
|
|
|
Right.isOneOf(tok::identifier, tok::kw_const)) ||
|
2017-02-06 18:55:49 +08:00
|
|
|
(Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
|
|
|
|
(Left.is(TT_TemplateOpener) && !Right.is(TT_TemplateCloser));
|
2013-01-30 05:01:14 +08:00
|
|
|
}
|
|
|
|
|
2013-04-09 04:33:42 +08:00
|
|
|
void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
|
2017-07-24 22:51:59 +08:00
|
|
|
llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n";
|
2013-05-29 22:47:47 +08:00
|
|
|
const FormatToken *Tok = Line.First;
|
2013-04-09 04:33:42 +08:00
|
|
|
while (Tok) {
|
2013-05-29 22:47:47 +08:00
|
|
|
llvm::errs() << " M=" << Tok->MustBreakBefore
|
2015-07-14 00:19:34 +08:00
|
|
|
<< " C=" << Tok->CanBreakBefore
|
|
|
|
<< " T=" << getTokenTypeName(Tok->Type)
|
2013-07-10 22:02:49 +08:00
|
|
|
<< " S=" << Tok->SpacesRequiredBefore
|
2014-06-10 22:44:02 +08:00
|
|
|
<< " B=" << Tok->BlockParameterCount
|
2017-09-20 17:51:03 +08:00
|
|
|
<< " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty
|
|
|
|
<< " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength
|
|
|
|
<< " PPK=" << Tok->PackingKind << " FakeLParens=";
|
2013-04-09 04:33:42 +08:00
|
|
|
for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i)
|
|
|
|
llvm::errs() << Tok->FakeLParens[i] << "/";
|
clang-format: Keep string-literal-label + value pairs on a line.
We have previously done that for <<-operators. This patch also adds
this logic for "," and "+".
Before:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " +
aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ",
aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
After:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
llvm-svn: 289531
2016-12-13 19:16:42 +08:00
|
|
|
llvm::errs() << " FakeRParens=" << Tok->FakeRParens;
|
2018-04-28 02:51:12 +08:00
|
|
|
llvm::errs() << " II=" << Tok->Tok.getIdentifierInfo();
|
clang-format: Keep string-literal-label + value pairs on a line.
We have previously done that for <<-operators. This patch also adds
this logic for "," and "+".
Before:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " +
aaaaaaaaaaaaaaaa + "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ",
aaaaaaaaaaaaaaaa, "aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
After:
string v = "aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa +
"aaaaaaaaaaaaaaaa: " + aaaaaaaaaaaaaaaa;
string v = StrCat("aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa,
"aaaaaaaaaaaaaaaa: ", aaaaaaaaaaaaaaaa);
llvm-svn: 289531
2016-12-13 19:16:42 +08:00
|
|
|
llvm::errs() << " Text='" << Tok->TokenText << "'\n";
|
2014-05-09 21:11:16 +08:00
|
|
|
if (!Tok->Next)
|
2013-10-12 05:25:45 +08:00
|
|
|
assert(Tok == Line.Last);
|
2013-05-29 22:47:47 +08:00
|
|
|
Tok = Tok->Next;
|
2013-04-09 04:33:42 +08:00
|
|
|
}
|
|
|
|
llvm::errs() << "----\n";
|
|
|
|
}
|
|
|
|
|
2013-01-30 05:01:14 +08:00
|
|
|
} // namespace format
|
|
|
|
} // namespace clang
|