2014-12-10 19:00:42 +00:00
|
|
|
//===--- UnwrappedLineFormatter.cpp - Format C++ code ---------------------===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2014-12-10 19:00:42 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "UnwrappedLineFormatter.h"
|
2023-02-01 13:20:28 +00:00
|
|
|
#include "FormatToken.h"
|
2019-03-01 09:09:54 +00:00
|
|
|
#include "NamespaceEndCommentsFixer.h"
|
2014-12-10 19:00:42 +00:00
|
|
|
#include "WhitespaceManager.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
2016-07-18 19:02:11 +00:00
|
|
|
#include <queue>
|
2014-12-10 19:00:42 +00:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "format-formatter"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace format {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool startsExternCBlock(const AnnotatedLine &Line) {
|
|
|
|
const FormatToken *Next = Line.First->getNextNonComment();
|
|
|
|
const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;
|
2015-06-17 09:43:56 +00:00
|
|
|
return Line.startsWith(tok::kw_extern) && Next && Next->isStringLiteral() &&
|
2014-12-10 19:00:42 +00:00
|
|
|
NextNext && NextNext->is(tok::l_brace);
|
|
|
|
}
|
|
|
|
|
2022-02-14 22:25:36 +01:00
|
|
|
bool isRecordLBrace(const FormatToken &Tok) {
|
|
|
|
return Tok.isOneOf(TT_ClassLBrace, TT_EnumLBrace, TT_RecordLBrace,
|
|
|
|
TT_StructLBrace, TT_UnionLBrace);
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Tracks the indent level of \c AnnotatedLines across levels.
|
2015-05-12 09:23:57 +00:00
|
|
|
///
|
|
|
|
/// \c nextLine must be called for each \c AnnotatedLine, after which \c
|
|
|
|
/// getIndent() will return the indent for the last line \c nextLine was called
|
|
|
|
/// with.
|
|
|
|
/// If the line is not formatted (and thus the indent does not change), calling
|
|
|
|
/// \c adjustToUnmodifiedLine after the call to \c nextLine will cause
|
|
|
|
/// subsequent lines on the same level to be indented at the same level as the
|
|
|
|
/// given line.
|
|
|
|
class LevelIndentTracker {
|
|
|
|
public:
|
|
|
|
LevelIndentTracker(const FormatStyle &Style,
|
|
|
|
const AdditionalKeywords &Keywords, unsigned StartLevel,
|
|
|
|
int AdditionalIndent)
|
2015-05-12 10:16:02 +00:00
|
|
|
: Style(Style), Keywords(Keywords), AdditionalIndent(AdditionalIndent) {
|
2015-05-12 09:23:57 +00:00
|
|
|
for (unsigned i = 0; i != StartLevel; ++i)
|
|
|
|
IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Returns the indent for the current line.
|
2015-05-12 09:23:57 +00:00
|
|
|
unsigned getIndent() const { return Indent; }
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Update the indent state given that \p Line is going to be formatted
|
2015-05-12 09:23:57 +00:00
|
|
|
/// next.
|
|
|
|
void nextLine(const AnnotatedLine &Line) {
|
|
|
|
Offset = getIndentOffset(*Line.First);
|
2015-06-11 10:14:13 +00:00
|
|
|
// Update the indent level cache size so that we can rely on it
|
|
|
|
// having the right size in adjustToUnmodifiedline.
|
2023-02-25 12:13:27 +02:00
|
|
|
if (Line.Level >= IndentForLevel.size())
|
|
|
|
IndentForLevel.resize(Line.Level + 1, -1);
|
2022-11-19 01:06:37 -08:00
|
|
|
if (Style.IndentPPDirectives != FormatStyle::PPDIS_None &&
|
|
|
|
(Line.InPPDirective ||
|
|
|
|
(Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
|
|
|
|
Line.Type == LT_CommentAbovePPDirective))) {
|
|
|
|
unsigned PPIndentWidth =
|
2021-06-03 16:56:56 +02:00
|
|
|
(Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth;
|
2022-11-19 01:06:37 -08:00
|
|
|
Indent = Line.InMacroBody
|
|
|
|
? Line.PPLevel * PPIndentWidth +
|
|
|
|
(Line.Level - Line.PPLevel) * Style.IndentWidth
|
|
|
|
: Line.Level * PPIndentWidth;
|
|
|
|
Indent += AdditionalIndent;
|
2015-05-12 09:23:57 +00:00
|
|
|
} else {
|
2021-12-03 16:59:34 +01:00
|
|
|
Indent = getIndent(Line.Level);
|
2015-05-12 09:23:57 +00:00
|
|
|
}
|
|
|
|
if (static_cast<int>(Indent) + Offset >= 0)
|
|
|
|
Indent += Offset;
|
2022-07-28 23:39:46 +00:00
|
|
|
if (Line.IsContinuation)
|
2020-03-19 12:49:15 +00:00
|
|
|
Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
|
2015-05-12 09:23:57 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Update the level indent to adapt to the given \p Line.
|
2015-05-12 09:23:57 +00:00
|
|
|
///
|
|
|
|
/// When a line is not formatted, we move the subsequent lines on the same
|
|
|
|
/// level to the same indent.
|
|
|
|
/// Note that \c nextLine must have been called before this method.
|
|
|
|
void adjustToUnmodifiedLine(const AnnotatedLine &Line) {
|
|
|
|
unsigned LevelIndent = Line.First->OriginalColumn;
|
|
|
|
if (static_cast<int>(LevelIndent) - Offset >= 0)
|
|
|
|
LevelIndent -= Offset;
|
2022-07-04 11:28:25 +02:00
|
|
|
assert(Line.Level < IndentForLevel.size());
|
2015-06-17 09:43:56 +00:00
|
|
|
if ((!Line.First->is(tok::comment) || IndentForLevel[Line.Level] == -1) &&
|
2022-05-21 21:51:19 -07:00
|
|
|
!Line.InPPDirective) {
|
2015-05-12 09:23:57 +00:00
|
|
|
IndentForLevel[Line.Level] = LevelIndent;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-12 09:23:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Get the offset of the line relatively to the level.
|
2015-05-12 09:23:57 +00:00
|
|
|
///
|
|
|
|
/// For example, 'public:' labels in classes are offset by 1 or 2
|
|
|
|
/// characters to the left from their level.
|
|
|
|
int getIndentOffset(const FormatToken &RootToken) {
|
2021-12-21 14:24:12 +00:00
|
|
|
if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
|
2022-05-21 21:51:19 -07:00
|
|
|
Style.isCSharp()) {
|
2015-05-12 09:23:57 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2022-01-30 20:45:32 +01:00
|
|
|
|
|
|
|
auto IsAccessModifier = [this, &RootToken]() {
|
2022-05-21 21:51:19 -07:00
|
|
|
if (RootToken.isAccessSpecifier(Style.isCpp())) {
|
2022-01-30 20:45:32 +01:00
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
} else if (RootToken.isObjCAccessSpecifier()) {
|
2022-01-30 20:45:32 +01:00
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2022-01-30 20:45:32 +01:00
|
|
|
// Handle Qt signals.
|
2023-07-11 16:55:45 -07:00
|
|
|
else if (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
|
|
|
|
RootToken.Next && RootToken.Next->is(tok::colon)) {
|
2022-01-30 20:45:32 +01:00
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
} else if (RootToken.Next &&
|
|
|
|
RootToken.Next->isOneOf(Keywords.kw_slots,
|
|
|
|
Keywords.kw_qslots) &&
|
|
|
|
RootToken.Next->Next && RootToken.Next->Next->is(tok::colon)) {
|
2022-01-30 20:45:32 +01:00
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2022-01-30 20:45:32 +01:00
|
|
|
// Handle malformed access specifier e.g. 'private' without trailing ':'.
|
2022-05-21 21:51:19 -07:00
|
|
|
else if (!RootToken.Next && RootToken.isAccessSpecifier(false)) {
|
2022-01-30 20:45:32 +01:00
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2022-01-30 20:45:32 +01:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (IsAccessModifier()) {
|
2021-09-20 18:48:34 -04:00
|
|
|
// The AccessModifierOffset may be overridden by IndentAccessModifiers,
|
[clang-format] [PR19056] Add support for access modifiers indentation
Adds support for coding styles that make a separate indentation level for access modifiers, such as Code::Blocks or QtCreator.
The new option, `IndentAccessModifiers`, if enabled, forces the content inside classes, structs and unions (“records”) to be indented twice while removing a level for access modifiers. The value of `AccessModifierOffset` is disregarded in this case, aiming towards an ease of use.
======
The PR (https://bugs.llvm.org/show_bug.cgi?id=19056) had an implementation attempt by @MyDeveloperDay already (https://reviews.llvm.org/D60225) but I've decided to start from scratch. They differ in functionality, chosen approaches, and even the option name. The code tries to re-use the existing functionality to achieve this behavior, limiting possibility of breaking something else.
Reviewed By: MyDeveloperDay, curdeius, HazardyKnusperkeks
Differential Revision: https://reviews.llvm.org/D94661
2021-02-26 09:05:35 +01:00
|
|
|
// in which case we take a negative value of the IndentWidth to simulate
|
|
|
|
// the upper indent level.
|
|
|
|
return Style.IndentAccessModifiers ? -Style.IndentWidth
|
|
|
|
: Style.AccessModifierOffset;
|
|
|
|
}
|
2015-05-12 09:23:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Get the indent of \p Level from \p IndentForLevel.
|
2015-05-12 09:23:57 +00:00
|
|
|
///
|
|
|
|
/// \p IndentForLevel must contain the indent for the level \c l
|
|
|
|
/// at \p IndentForLevel[l], or a value < 0 if the indent for
|
|
|
|
/// that level is unknown.
|
2021-12-03 16:59:34 +01:00
|
|
|
unsigned getIndent(unsigned Level) const {
|
2015-05-12 09:23:57 +00:00
|
|
|
if (IndentForLevel[Level] != -1)
|
|
|
|
return IndentForLevel[Level];
|
|
|
|
if (Level == 0)
|
|
|
|
return 0;
|
2021-12-03 16:59:34 +01:00
|
|
|
return getIndent(Level - 1) + Style.IndentWidth;
|
2015-05-12 09:23:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const FormatStyle &Style;
|
|
|
|
const AdditionalKeywords &Keywords;
|
2015-05-12 11:14:06 +00:00
|
|
|
const unsigned AdditionalIndent;
|
2015-05-12 10:16:02 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// The indent in characters for each level.
|
2022-07-04 21:59:43 -07:00
|
|
|
SmallVector<int> IndentForLevel;
|
2015-05-12 09:23:57 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Offset of the current line relative to the indent level.
|
2015-05-12 09:23:57 +00:00
|
|
|
///
|
|
|
|
/// For example, the 'public' keywords is often indented with a negative
|
|
|
|
/// offset.
|
|
|
|
int Offset = 0;
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// The current line's indent.
|
2015-05-12 09:23:57 +00:00
|
|
|
unsigned Indent = 0;
|
|
|
|
};
|
|
|
|
|
2019-06-06 20:06:23 +00:00
|
|
|
const FormatToken *getMatchingNamespaceToken(
|
|
|
|
const AnnotatedLine *Line,
|
|
|
|
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
|
2017-06-14 12:29:47 +00:00
|
|
|
if (!Line->startsWith(tok::r_brace))
|
2019-06-06 20:06:23 +00:00
|
|
|
return nullptr;
|
2017-06-14 12:29:47 +00:00
|
|
|
size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
|
|
|
|
if (StartLineIndex == UnwrappedLine::kInvalidIndex)
|
2019-06-06 20:06:23 +00:00
|
|
|
return nullptr;
|
2017-06-14 12:29:47 +00:00
|
|
|
assert(StartLineIndex < AnnotatedLines.size());
|
2019-06-06 20:06:23 +00:00
|
|
|
return AnnotatedLines[StartLineIndex]->First->getNamespaceToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getNamespaceTokenText(const AnnotatedLine *Line) {
|
|
|
|
const FormatToken *NamespaceToken = Line->First->getNamespaceToken();
|
|
|
|
return NamespaceToken ? NamespaceToken->TokenText : StringRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getMatchingNamespaceTokenText(
|
|
|
|
const AnnotatedLine *Line,
|
|
|
|
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
|
|
|
|
const FormatToken *NamespaceToken =
|
|
|
|
getMatchingNamespaceToken(Line, AnnotatedLines);
|
|
|
|
return NamespaceToken ? NamespaceToken->TokenText : StringRef();
|
2017-06-14 12:29:47 +00:00
|
|
|
}
|
|
|
|
|
2014-12-10 19:00:42 +00:00
|
|
|
class LineJoiner {
|
|
|
|
public:
|
2015-05-12 09:23:57 +00:00
|
|
|
LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords,
|
|
|
|
const SmallVectorImpl<AnnotatedLine *> &Lines)
|
2017-06-14 12:29:47 +00:00
|
|
|
: Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()),
|
|
|
|
AnnotatedLines(Lines) {}
|
2015-05-12 09:23:57 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Returns the next line, merging multiple lines into one if possible.
|
2015-05-12 09:23:57 +00:00
|
|
|
const AnnotatedLine *getNextMergedLine(bool DryRun,
|
|
|
|
LevelIndentTracker &IndentTracker) {
|
|
|
|
if (Next == End)
|
|
|
|
return nullptr;
|
|
|
|
const AnnotatedLine *Current = *Next;
|
|
|
|
IndentTracker.nextLine(*Current);
|
2017-09-20 09:51:03 +00:00
|
|
|
unsigned MergedLines = tryFitMultipleLinesInOne(IndentTracker, Next, End);
|
2022-05-21 21:51:19 -07:00
|
|
|
if (MergedLines > 0 && Style.ColumnLimit == 0) {
|
2015-05-12 09:23:57 +00:00
|
|
|
// Disallow line merging if there is a break at the start of one of the
|
|
|
|
// input lines.
|
|
|
|
for (unsigned i = 0; i < MergedLines; ++i)
|
|
|
|
if (Next[i + 1]->First->NewlinesBefore > 0)
|
|
|
|
MergedLines = 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-12 09:23:57 +00:00
|
|
|
if (!DryRun)
|
|
|
|
for (unsigned i = 0; i < MergedLines; ++i)
|
2016-11-15 15:07:07 +00:00
|
|
|
join(*Next[0], *Next[i + 1]);
|
2015-05-12 09:23:57 +00:00
|
|
|
Next = Next + MergedLines + 1;
|
|
|
|
return Current;
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2015-05-12 09:23:57 +00:00
|
|
|
private:
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Calculates how many lines can be merged into 1 starting at \p I.
|
2014-12-10 19:00:42 +00:00
|
|
|
unsigned
|
2017-06-14 12:29:47 +00:00
|
|
|
tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
|
2014-12-10 19:00:42 +00:00
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
|
2017-06-14 12:29:47 +00:00
|
|
|
const unsigned Indent = IndentTracker.getIndent();
|
|
|
|
|
2015-03-13 13:32:11 +00:00
|
|
|
// Can't join the last line with anything.
|
|
|
|
if (I + 1 == E)
|
|
|
|
return 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
// We can never merge stuff if there are trailing line comments.
|
|
|
|
const AnnotatedLine *TheLine = *I;
|
|
|
|
if (TheLine->Last->is(TT_LineComment))
|
|
|
|
return 0;
|
2021-12-03 08:13:57 +01:00
|
|
|
const auto &NextLine = *I[1];
|
|
|
|
if (NextLine.Type == LT_Invalid || NextLine.First->MustBreakBefore)
|
2015-03-13 13:32:11 +00:00
|
|
|
return 0;
|
|
|
|
if (TheLine->InPPDirective &&
|
2022-05-21 21:51:19 -07:00
|
|
|
(!NextLine.InPPDirective || NextLine.First->HasUnescapedNewline)) {
|
2015-03-13 13:32:11 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
|
|
|
if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsigned Limit =
|
|
|
|
Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
|
|
|
|
// If we already exceed the column limit, we set 'Limit' to 0. The different
|
|
|
|
// tryMerge..() functions can then decide whether to still do merging.
|
|
|
|
Limit = TheLine->Last->TotalLength > Limit
|
|
|
|
? 0
|
|
|
|
: Limit - TheLine->Last->TotalLength;
|
|
|
|
|
2017-06-13 07:02:43 +00:00
|
|
|
if (TheLine->Last->is(TT_FunctionLBrace) &&
|
|
|
|
TheLine->First == TheLine->Last &&
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
!Style.BraceWrapping.SplitEmptyFunction &&
|
2022-05-21 21:51:19 -07:00
|
|
|
NextLine.First->is(tok::r_brace)) {
|
2017-06-13 07:02:43 +00:00
|
|
|
return tryMergeSimpleBlock(I, E, Limit);
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2017-06-13 07:02:43 +00:00
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
const auto *PreviousLine = I != AnnotatedLines.begin() ? I[-1] : nullptr;
|
|
|
|
// Handle empty record blocks where the brace has already been wrapped.
|
|
|
|
if (PreviousLine && TheLine->Last->is(tok::l_brace) &&
|
|
|
|
TheLine->First == TheLine->Last) {
|
|
|
|
bool EmptyBlock = NextLine.First->is(tok::r_brace);
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
const FormatToken *Tok = PreviousLine->First;
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
if (Tok && Tok->is(tok::comment))
|
|
|
|
Tok = Tok->getNextNonComment();
|
|
|
|
|
2022-05-21 21:51:19 -07:00
|
|
|
if (Tok && Tok->getNamespaceToken()) {
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock
|
2017-09-20 09:51:03 +00:00
|
|
|
? tryMergeSimpleBlock(I, E, Limit)
|
|
|
|
: 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
|
|
|
|
if (Tok && Tok->is(tok::kw_typedef))
|
|
|
|
Tok = Tok->getNextNonComment();
|
|
|
|
if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
|
2022-05-21 21:51:19 -07:00
|
|
|
tok::kw_extern, Keywords.kw_interface)) {
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
|
2017-09-15 11:23:50 +00:00
|
|
|
? tryMergeSimpleBlock(I, E, Limit)
|
|
|
|
: 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2021-01-17 11:13:50 +00:00
|
|
|
|
|
|
|
if (Tok && Tok->is(tok::kw_template) &&
|
2022-05-21 21:51:19 -07:00
|
|
|
Style.BraceWrapping.SplitEmptyRecord && EmptyBlock) {
|
2021-01-17 11:13:50 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
clang-format: add options to merge empty record body
Summary:
This patch introduces a few extra BraceWrapping options, similar to
`SplitEmptyFunction`, to allow merging empty 'record' bodies (e.g.
class, struct, union and namespace):
* SplitEmptyClass
* SplitEmptyStruct
* SplitEmptyUnion
* SplitEmptyNamespace
The `SplitEmptyFunction` option name has also been simplified/
shortened (from `SplitEmptyFunctionBody`).
These options are helpful when the correspond AfterXXX option is
enabled, to allow merging the empty record:
class Foo
{};
In addition, this fixes an unexpected merging of short records, when
the AfterXXXX options are used, which caused to be formatted like
this:
class Foo
{ void Foo(); };
This is now properly formatted as:
class Foo
{
void Foo();
};
Reviewers: djasper, krasimir
Reviewed By: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D34395
llvm-svn: 306874
2017-06-30 20:25:55 +00:00
|
|
|
}
|
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
auto ShouldMergeShortFunctions = [this, &I, &NextLine, PreviousLine,
|
|
|
|
TheLine]() {
|
|
|
|
if (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All)
|
|
|
|
return true;
|
|
|
|
if (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
|
2022-05-21 21:51:19 -07:00
|
|
|
NextLine.First->is(tok::r_brace)) {
|
2021-12-03 08:13:57 +01:00
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2022-01-14 21:51:06 +01:00
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
if (Style.AllowShortFunctionsOnASingleLine &
|
|
|
|
FormatStyle::SFS_InlineOnly) {
|
|
|
|
// Just checking TheLine->Level != 0 is not enough, because it
|
|
|
|
// provokes treating functions inside indented namespaces as short.
|
|
|
|
if (Style.isJavaScript() && TheLine->Last->is(TT_FunctionLBrace))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (TheLine->Level != 0) {
|
|
|
|
if (!PreviousLine)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// TODO: Use IndentTracker to avoid loop?
|
|
|
|
// Find the last line with lower level.
|
2022-04-20 23:53:17 -07:00
|
|
|
const AnnotatedLine *Line = nullptr;
|
|
|
|
for (auto J = I - 1; J >= AnnotatedLines.begin(); --J) {
|
|
|
|
assert(*J);
|
|
|
|
if (!(*J)->InPPDirective && !(*J)->isComment() &&
|
|
|
|
(*J)->Level < TheLine->Level) {
|
|
|
|
Line = *J;
|
|
|
|
break;
|
2022-04-19 13:02:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-20 23:53:17 -07:00
|
|
|
if (!Line)
|
2022-03-03 15:37:43 +01:00
|
|
|
return false;
|
2021-12-03 08:13:57 +01:00
|
|
|
|
|
|
|
// Check if the found line starts a record.
|
2022-04-20 23:53:17 -07:00
|
|
|
const FormatToken *LastNonComment = Line->Last;
|
2022-02-16 23:05:34 +01:00
|
|
|
assert(LastNonComment);
|
|
|
|
if (LastNonComment->is(tok::comment)) {
|
|
|
|
LastNonComment = LastNonComment->getPreviousNonComment();
|
|
|
|
// There must be another token (usually `{`), because we chose a
|
2022-04-20 23:53:17 -07:00
|
|
|
// non-PPDirective and non-comment line that has a smaller level.
|
2022-02-16 23:05:34 +01:00
|
|
|
assert(LastNonComment);
|
|
|
|
}
|
|
|
|
return isRecordLBrace(*LastNonComment);
|
2021-12-03 08:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
2022-01-14 21:51:06 +01:00
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool MergeShortFunctions = ShouldMergeShortFunctions();
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2022-02-11 14:53:36 +01:00
|
|
|
const FormatToken *FirstNonComment = TheLine->First;
|
|
|
|
if (FirstNonComment->is(tok::comment)) {
|
|
|
|
FirstNonComment = FirstNonComment->getNextNonComment();
|
|
|
|
if (!FirstNonComment)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// FIXME: There are probably cases where we should use FirstNonComment
|
|
|
|
// instead of TheLine->First.
|
|
|
|
|
2017-06-14 12:29:47 +00:00
|
|
|
if (Style.CompactNamespaces) {
|
2023-02-25 12:13:27 +02:00
|
|
|
if (const auto *NSToken = TheLine->First->getNamespaceToken()) {
|
|
|
|
int J = 1;
|
|
|
|
assert(TheLine->MatchingClosingBlockLineIndex > 0);
|
|
|
|
for (auto ClosingLineIndex = TheLine->MatchingClosingBlockLineIndex - 1;
|
|
|
|
I + J != E && NSToken->TokenText == getNamespaceTokenText(I[J]) &&
|
|
|
|
ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
|
|
|
|
I[J]->Last->TotalLength < Limit;
|
|
|
|
++J, --ClosingLineIndex) {
|
|
|
|
Limit -= I[J]->Last->TotalLength;
|
|
|
|
|
|
|
|
// Reduce indent level for bodies of namespaces which were compacted,
|
|
|
|
// but only if their content was indented in the first place.
|
|
|
|
auto *ClosingLine = AnnotatedLines.begin() + ClosingLineIndex + 1;
|
|
|
|
auto OutdentBy = I[J]->Level - TheLine->Level;
|
|
|
|
for (auto *CompactedLine = I + J; CompactedLine <= ClosingLine;
|
|
|
|
++CompactedLine) {
|
|
|
|
if (!(*CompactedLine)->InPPDirective)
|
|
|
|
(*CompactedLine)->Level -= OutdentBy;
|
|
|
|
}
|
2017-06-14 12:29:47 +00:00
|
|
|
}
|
2023-02-25 12:13:27 +02:00
|
|
|
return J - 1;
|
2017-06-14 12:29:47 +00:00
|
|
|
}
|
|
|
|
|
2019-06-06 20:06:23 +00:00
|
|
|
if (auto nsToken = getMatchingNamespaceToken(TheLine, AnnotatedLines)) {
|
2017-06-14 12:29:47 +00:00
|
|
|
int i = 0;
|
|
|
|
unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
|
2019-06-06 20:06:23 +00:00
|
|
|
for (; I + 1 + i != E &&
|
|
|
|
nsToken->TokenText ==
|
|
|
|
getMatchingNamespaceTokenText(I[i + 1], AnnotatedLines) &&
|
2017-06-14 12:29:47 +00:00
|
|
|
openingLine == I[i + 1]->MatchingOpeningBlockLineIndex;
|
2022-02-02 14:01:12 +01:00
|
|
|
i++, --openingLine) {
|
2021-12-03 08:13:57 +01:00
|
|
|
// No space between consecutive braces.
|
2017-06-14 12:29:47 +00:00
|
|
|
I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace);
|
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
// Indent like the outer-most namespace.
|
2017-06-14 12:29:47 +00:00
|
|
|
IndentTracker.nextLine(*I[i + 1]);
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
// Try to merge a function block with left brace unwrapped.
|
2022-02-02 15:00:40 +01:00
|
|
|
if (TheLine->Last->is(TT_FunctionLBrace) && TheLine->First != TheLine->Last)
|
2014-12-10 19:00:42 +00:00
|
|
|
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
|
2021-12-03 08:13:57 +01:00
|
|
|
// Try to merge a control statement block with left brace unwrapped.
|
2022-02-11 14:53:36 +01:00
|
|
|
if (TheLine->Last->is(tok::l_brace) && FirstNonComment != TheLine->Last &&
|
|
|
|
FirstNonComment->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for,
|
|
|
|
TT_ForEachMacro)) {
|
2019-08-11 17:48:36 +00:00
|
|
|
return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
? tryMergeSimpleBlock(I, E, Limit)
|
|
|
|
: 0;
|
|
|
|
}
|
2021-12-03 08:13:57 +01:00
|
|
|
// Try to merge a control statement block with left brace wrapped.
|
|
|
|
if (NextLine.First->is(tok::l_brace)) {
|
|
|
|
if ((TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
|
|
|
|
tok::kw_for, tok::kw_switch, tok::kw_try,
|
|
|
|
tok::kw_do, TT_ForEachMacro) ||
|
|
|
|
(TheLine->First->is(tok::r_brace) && TheLine->First->Next &&
|
|
|
|
TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) &&
|
|
|
|
Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_MultiLine) {
|
|
|
|
// If possible, merge the next line's wrapped left brace with the
|
|
|
|
// current line. Otherwise, leave it on the next line, as this is a
|
|
|
|
// multi-line control statement.
|
2022-05-21 15:10:21 -07:00
|
|
|
return (Style.ColumnLimit == 0 || TheLine->Level * Style.IndentWidth +
|
|
|
|
TheLine->Last->TotalLength <=
|
|
|
|
Style.ColumnLimit)
|
2021-12-03 08:13:57 +01:00
|
|
|
? 1
|
|
|
|
: 0;
|
|
|
|
}
|
|
|
|
if (TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
|
|
|
|
tok::kw_for, TT_ForEachMacro)) {
|
|
|
|
return (Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always)
|
|
|
|
? tryMergeSimpleBlock(I, E, Limit)
|
|
|
|
: 0;
|
|
|
|
}
|
|
|
|
if (TheLine->First->isOneOf(tok::kw_else, tok::kw_catch) &&
|
|
|
|
Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_MultiLine) {
|
|
|
|
// This case if different from the upper BWACS_MultiLine processing
|
|
|
|
// in that a preceding r_brace is not on the same line as else/catch
|
|
|
|
// most likely because of BeforeElse/BeforeCatch set to true.
|
|
|
|
// If the line length doesn't fit ColumnLimit, leave l_brace on the
|
|
|
|
// next line to respect the BWACS_MultiLine.
|
|
|
|
return (Style.ColumnLimit == 0 ||
|
|
|
|
TheLine->Last->TotalLength <= Style.ColumnLimit)
|
|
|
|
? 1
|
|
|
|
: 0;
|
|
|
|
}
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
}
|
2021-12-03 08:13:57 +01:00
|
|
|
if (PreviousLine && TheLine->First->is(tok::l_brace)) {
|
|
|
|
switch (PreviousLine->First->Tok.getKind()) {
|
|
|
|
case tok::at:
|
|
|
|
// Don't merge block with left brace wrapped after ObjC special blocks.
|
|
|
|
if (PreviousLine->First->Next) {
|
|
|
|
tok::ObjCKeywordKind kwId =
|
|
|
|
PreviousLine->First->Next->Tok.getObjCKeywordID();
|
|
|
|
if (kwId == tok::objc_autoreleasepool ||
|
2022-05-21 21:51:19 -07:00
|
|
|
kwId == tok::objc_synchronized) {
|
2021-12-03 08:13:57 +01:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2021-12-03 08:13:57 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw_case:
|
|
|
|
case tok::kw_default:
|
|
|
|
// Don't merge block with left brace wrapped after case labels.
|
2018-02-27 13:48:27 +00:00
|
|
|
return 0;
|
2021-12-03 08:13:57 +01:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-02-27 13:48:27 +00:00
|
|
|
}
|
2021-01-17 11:13:50 +00:00
|
|
|
|
|
|
|
// Don't merge an empty template class or struct if SplitEmptyRecords
|
|
|
|
// is defined.
|
2021-12-03 08:13:57 +01:00
|
|
|
if (PreviousLine && Style.BraceWrapping.SplitEmptyRecord &&
|
|
|
|
TheLine->Last->is(tok::l_brace) && PreviousLine->Last) {
|
|
|
|
const FormatToken *Previous = PreviousLine->Last;
|
2021-01-17 11:13:50 +00:00
|
|
|
if (Previous) {
|
|
|
|
if (Previous->is(tok::comment))
|
|
|
|
Previous = Previous->getPreviousNonComment();
|
|
|
|
if (Previous) {
|
2021-12-03 08:13:57 +01:00
|
|
|
if (Previous->is(tok::greater) && !PreviousLine->InPPDirective)
|
2021-01-17 11:13:50 +00:00
|
|
|
return 0;
|
|
|
|
if (Previous->is(tok::identifier)) {
|
|
|
|
const FormatToken *PreviousPrevious =
|
|
|
|
Previous->getPreviousNonComment();
|
|
|
|
if (PreviousPrevious &&
|
2022-05-21 21:51:19 -07:00
|
|
|
PreviousPrevious->isOneOf(tok::kw_class, tok::kw_struct)) {
|
2021-01-17 11:13:50 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2021-01-17 11:13:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-10 19:00:42 +00:00
|
|
|
if (TheLine->Last->is(tok::l_brace)) {
|
2021-12-21 16:44:44 +01:00
|
|
|
bool ShouldMerge = false;
|
2022-02-14 22:25:36 +01:00
|
|
|
// Try to merge records.
|
|
|
|
if (TheLine->Last->is(TT_EnumLBrace)) {
|
|
|
|
ShouldMerge = Style.AllowShortEnumsOnASingleLine;
|
|
|
|
} else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) {
|
|
|
|
// NOTE: We use AfterClass (whereas AfterStruct exists) for both classes
|
|
|
|
// and structs, but it seems that wrapping is still handled correctly
|
|
|
|
// elsewhere.
|
2021-12-21 16:44:44 +01:00
|
|
|
ShouldMerge = !Style.BraceWrapping.AfterClass ||
|
2021-12-03 08:13:57 +01:00
|
|
|
(NextLine.First->is(tok::r_brace) &&
|
2021-12-21 16:44:44 +01:00
|
|
|
!Style.BraceWrapping.SplitEmptyRecord);
|
2023-04-21 11:56:37 +00:00
|
|
|
} else if (TheLine->InPPDirective ||
|
|
|
|
!TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
|
|
|
|
tok::kw_struct)) {
|
2022-02-14 22:25:36 +01:00
|
|
|
// Try to merge a block with left brace unwrapped that wasn't yet
|
|
|
|
// covered.
|
2021-12-21 16:44:44 +01:00
|
|
|
ShouldMerge = !Style.BraceWrapping.AfterFunction ||
|
2021-12-03 08:13:57 +01:00
|
|
|
(NextLine.First->is(tok::r_brace) &&
|
2021-12-21 16:44:44 +01:00
|
|
|
!Style.BraceWrapping.SplitEmptyFunction);
|
|
|
|
}
|
|
|
|
return ShouldMerge ? tryMergeSimpleBlock(I, E, Limit) : 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
2022-02-14 22:25:36 +01:00
|
|
|
|
2021-12-03 08:13:57 +01:00
|
|
|
// Try to merge a function block with left brace wrapped.
|
|
|
|
if (NextLine.First->is(TT_FunctionLBrace) &&
|
2015-09-29 14:57:55 +00:00
|
|
|
Style.BraceWrapping.AfterFunction) {
|
2021-12-03 08:13:57 +01:00
|
|
|
if (NextLine.Last->is(TT_LineComment))
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Check for Limit <= 2 to account for the " {".
|
|
|
|
if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
|
|
|
|
return 0;
|
|
|
|
Limit -= 2;
|
|
|
|
|
|
|
|
unsigned MergedLines = 0;
|
2017-06-13 07:02:43 +00:00
|
|
|
if (MergeShortFunctions ||
|
|
|
|
(Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
|
2021-12-03 08:13:57 +01:00
|
|
|
NextLine.First == NextLine.Last && I + 2 != E &&
|
2017-06-13 07:02:43 +00:00
|
|
|
I[2]->First->is(tok::r_brace))) {
|
2014-12-10 19:00:42 +00:00
|
|
|
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
|
|
|
|
// If we managed to merge the block, count the function header, which is
|
|
|
|
// on a separate line.
|
|
|
|
if (MergedLines > 0)
|
|
|
|
++MergedLines;
|
|
|
|
}
|
|
|
|
return MergedLines;
|
|
|
|
}
|
2021-05-03 18:52:19 +02:00
|
|
|
auto IsElseLine = [&TheLine]() -> bool {
|
|
|
|
const FormatToken *First = TheLine->First;
|
2021-05-03 17:59:32 +02:00
|
|
|
if (First->is(tok::kw_else))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return First->is(tok::r_brace) && First->Next &&
|
|
|
|
First->Next->is(tok::kw_else);
|
|
|
|
};
|
|
|
|
if (TheLine->First->is(tok::kw_if) ||
|
|
|
|
(IsElseLine() && (Style.AllowShortIfStatementsOnASingleLine ==
|
|
|
|
FormatStyle::SIS_AllIfsAndElse))) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return Style.AllowShortIfStatementsOnASingleLine
|
|
|
|
? tryMergeSimpleControlStatement(I, E, Limit)
|
|
|
|
: 0;
|
|
|
|
}
|
2022-01-14 21:59:40 +01:00
|
|
|
if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while, tok::kw_do,
|
|
|
|
TT_ForEachMacro)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return Style.AllowShortLoopsOnASingleLine
|
|
|
|
? tryMergeSimpleControlStatement(I, E, Limit)
|
|
|
|
: 0;
|
|
|
|
}
|
|
|
|
if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
|
|
|
|
return Style.AllowShortCaseLabelsOnASingleLine
|
|
|
|
? tryMergeShortCaseLabels(I, E, Limit)
|
|
|
|
: 0;
|
|
|
|
}
|
|
|
|
if (TheLine->InPPDirective &&
|
2022-05-21 21:51:19 -07:00
|
|
|
(TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return tryMergeSimplePPDirective(I, E, Limit);
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
|
|
|
|
unsigned Limit) {
|
|
|
|
if (Limit == 0)
|
|
|
|
return 0;
|
|
|
|
if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
|
|
|
|
return 0;
|
|
|
|
if (1 + I[1]->Last->TotalLength > Limit)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned tryMergeSimpleControlStatement(
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
|
|
|
|
if (Limit == 0)
|
|
|
|
return 0;
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
if (Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always &&
|
2019-08-11 17:48:36 +00:00
|
|
|
I[1]->First->is(tok::l_brace) &&
|
2022-05-21 21:51:19 -07:00
|
|
|
Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
if (I[1]->InPPDirective != (*I)->InPPDirective ||
|
2022-05-21 21:51:19 -07:00
|
|
|
(I[1]->InPPDirective && I[1]->First->HasUnescapedNewline)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
Limit = limitConsideringMacros(I + 1, E, Limit);
|
|
|
|
AnnotatedLine &Line = **I;
|
2021-05-03 17:59:32 +02:00
|
|
|
if (!Line.First->is(tok::kw_do) && !Line.First->is(tok::kw_else) &&
|
2022-05-21 21:51:19 -07:00
|
|
|
!Line.Last->is(tok::kw_else) && Line.Last->isNot(tok::r_paren)) {
|
2020-03-06 11:13:23 -05:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2022-01-14 21:59:40 +01:00
|
|
|
// Only merge `do while` if `do` is the only statement on the line.
|
2020-03-06 11:13:23 -05:00
|
|
|
if (Line.First->is(tok::kw_do) && !Line.Last->is(tok::kw_do))
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
|
|
|
if (1 + I[1]->Last->TotalLength > Limit)
|
|
|
|
return 0;
|
2022-01-14 21:59:40 +01:00
|
|
|
// Don't merge with loops, ifs, a single semicolon or a line comment.
|
2015-05-11 08:21:35 +00:00
|
|
|
if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, tok::kw_while,
|
2022-05-21 21:51:19 -07:00
|
|
|
TT_ForEachMacro, TT_LineComment)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2019-03-13 08:26:39 +00:00
|
|
|
// Only inline simple if's (no nested if or else), unless specified
|
2021-05-03 17:59:32 +02:00
|
|
|
if (Style.AllowShortIfStatementsOnASingleLine ==
|
|
|
|
FormatStyle::SIS_WithoutElse) {
|
2019-03-13 08:26:39 +00:00
|
|
|
if (I + 2 != E && Line.startsWith(tok::kw_if) &&
|
2022-05-21 21:51:19 -07:00
|
|
|
I[2]->First->is(tok::kw_else)) {
|
2019-03-13 08:26:39 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2019-03-13 08:26:39 +00:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-11 08:21:35 +00:00
|
|
|
unsigned
|
|
|
|
tryMergeShortCaseLabels(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
|
|
|
|
unsigned Limit) {
|
2014-12-10 19:00:42 +00:00
|
|
|
if (Limit == 0 || I + 1 == E ||
|
2022-05-21 21:51:19 -07:00
|
|
|
I[1]->First->isOneOf(tok::kw_case, tok::kw_default)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2018-09-21 03:46:36 +00:00
|
|
|
if (I[0]->Last->is(tok::l_brace) || I[1]->First->is(tok::l_brace))
|
|
|
|
return 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
unsigned NumStmts = 0;
|
|
|
|
unsigned Length = 0;
|
2017-07-28 07:56:18 +00:00
|
|
|
bool EndsWithComment = false;
|
2014-12-10 19:00:42 +00:00
|
|
|
bool InPPDirective = I[0]->InPPDirective;
|
2022-10-10 19:57:17 -07:00
|
|
|
bool InMacroBody = I[0]->InMacroBody;
|
2017-07-28 07:56:18 +00:00
|
|
|
const unsigned Level = I[0]->Level;
|
2014-12-10 19:00:42 +00:00
|
|
|
for (; NumStmts < 3; ++NumStmts) {
|
|
|
|
if (I + 1 + NumStmts == E)
|
|
|
|
break;
|
|
|
|
const AnnotatedLine *Line = I[1 + NumStmts];
|
|
|
|
if (Line->InPPDirective != InPPDirective)
|
|
|
|
break;
|
2022-10-10 19:57:17 -07:00
|
|
|
if (Line->InMacroBody != InMacroBody)
|
|
|
|
break;
|
2014-12-10 19:00:42 +00:00
|
|
|
if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
|
|
|
|
break;
|
|
|
|
if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
|
2017-07-28 07:56:18 +00:00
|
|
|
tok::kw_while) ||
|
2022-05-21 21:51:19 -07:00
|
|
|
EndsWithComment) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2017-07-28 07:56:18 +00:00
|
|
|
if (Line->First->is(tok::comment)) {
|
|
|
|
if (Level != Line->Level)
|
|
|
|
return 0;
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts;
|
|
|
|
for (; J != E; ++J) {
|
|
|
|
Line = *J;
|
|
|
|
if (Line->InPPDirective != InPPDirective)
|
|
|
|
break;
|
|
|
|
if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
|
|
|
|
break;
|
|
|
|
if (Line->First->isNot(tok::comment) || Level != Line->Level)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Line->Last->is(tok::comment))
|
|
|
|
EndsWithComment = true;
|
2014-12-10 19:00:42 +00:00
|
|
|
Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
|
|
|
|
}
|
|
|
|
if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
|
|
|
|
return 0;
|
|
|
|
return NumStmts;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
|
|
|
|
unsigned Limit) {
|
2022-02-03 18:46:35 +01:00
|
|
|
// Don't merge with a preprocessor directive.
|
|
|
|
if (I[1]->Type == LT_PreprocessorDirective)
|
|
|
|
return 0;
|
|
|
|
|
2014-12-10 19:00:42 +00:00
|
|
|
AnnotatedLine &Line = **I;
|
|
|
|
|
|
|
|
// Don't merge ObjC @ keywords and methods.
|
2015-02-07 01:57:32 +00:00
|
|
|
// FIXME: If an option to allow short exception handling clauses on a single
|
|
|
|
// line is added, change this to not return for @try and friends.
|
2014-12-10 19:00:42 +00:00
|
|
|
if (Style.Language != FormatStyle::LK_Java &&
|
2022-05-21 21:51:19 -07:00
|
|
|
Line.First->isOneOf(tok::at, tok::minus, tok::plus)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
|
|
|
// Check that the current line allows merging. This depends on whether we
|
|
|
|
// are in a control flow statements as well as several style flags.
|
2021-11-25 19:42:40 +00:00
|
|
|
if (Line.First->is(tok::kw_case) ||
|
2022-05-21 21:51:19 -07:00
|
|
|
(Line.First->Next && Line.First->Next->is(tok::kw_else))) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2018-09-02 09:04:51 +00:00
|
|
|
// default: in switch statement
|
|
|
|
if (Line.First->is(tok::kw_default)) {
|
|
|
|
const FormatToken *Tok = Line.First->getNextNonComment();
|
|
|
|
if (Tok && Tok->is(tok::colon))
|
|
|
|
return 0;
|
|
|
|
}
|
2022-08-31 23:19:08 -07:00
|
|
|
|
|
|
|
auto IsCtrlStmt = [](const auto &Line) {
|
|
|
|
return Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
|
|
|
|
tok::kw_do, tok::kw_for, TT_ForEachMacro);
|
|
|
|
};
|
|
|
|
|
|
|
|
const bool IsSplitBlock =
|
|
|
|
Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never ||
|
|
|
|
(Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty &&
|
|
|
|
I[1]->First->isNot(tok::r_brace));
|
|
|
|
|
|
|
|
if (IsCtrlStmt(Line) ||
|
|
|
|
Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
|
|
|
|
tok::kw___finally, tok::r_brace,
|
|
|
|
Keywords.kw___except)) {
|
|
|
|
if (IsSplitBlock)
|
2021-12-15 23:05:24 +00:00
|
|
|
return 0;
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// Don't merge when we can't except the case when
|
|
|
|
// the control statement block is empty
|
|
|
|
if (!Style.AllowShortIfStatementsOnASingleLine &&
|
2021-11-25 19:42:40 +00:00
|
|
|
Line.First->isOneOf(tok::kw_if, tok::kw_else) &&
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
!Style.BraceWrapping.AfterControlStatement &&
|
2022-05-21 21:51:19 -07:00
|
|
|
!I[1]->First->is(tok::r_brace)) {
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
if (!Style.AllowShortIfStatementsOnASingleLine &&
|
2021-11-25 19:42:40 +00:00
|
|
|
Line.First->isOneOf(tok::kw_if, tok::kw_else) &&
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always &&
|
2022-05-21 21:51:19 -07:00
|
|
|
I + 2 != E && !I[2]->First->is(tok::r_brace)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
if (!Style.AllowShortLoopsOnASingleLine &&
|
2022-01-14 21:59:40 +01:00
|
|
|
Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for,
|
|
|
|
TT_ForEachMacro) &&
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
!Style.BraceWrapping.AfterControlStatement &&
|
2022-05-21 21:51:19 -07:00
|
|
|
!I[1]->First->is(tok::r_brace)) {
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
if (!Style.AllowShortLoopsOnASingleLine &&
|
2022-01-14 21:59:40 +01:00
|
|
|
Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for,
|
|
|
|
TT_ForEachMacro) &&
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always &&
|
2022-05-21 21:51:19 -07:00
|
|
|
I + 2 != E && !I[2]->First->is(tok::r_brace)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
// FIXME: Consider an option to allow short exception handling clauses on
|
|
|
|
// a single line.
|
2015-02-04 15:26:27 +00:00
|
|
|
// FIXME: This isn't covered by tests.
|
|
|
|
// FIXME: For catch, __except, __finally the first token on the line
|
|
|
|
// is '}', so this isn't correct here.
|
|
|
|
if (Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
|
2022-05-21 21:51:19 -07:00
|
|
|
Keywords.kw___except, tok::kw___finally)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
if (Line.Last->is(tok::l_brace)) {
|
2022-08-31 23:19:08 -07:00
|
|
|
if (IsSplitBlock && Line.First == Line.Last &&
|
|
|
|
I > AnnotatedLines.begin() &&
|
|
|
|
(I[-1]->endsWith(tok::kw_else) || IsCtrlStmt(*I[-1]))) {
|
|
|
|
return 0;
|
|
|
|
}
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
FormatToken *Tok = I[1]->First;
|
2022-02-11 15:15:18 +01:00
|
|
|
auto ShouldMerge = [Tok]() {
|
|
|
|
if (Tok->isNot(tok::r_brace) || Tok->MustBreakBefore)
|
|
|
|
return false;
|
|
|
|
const FormatToken *Next = Tok->getNextNonComment();
|
|
|
|
return !Next || Next->is(tok::semi);
|
|
|
|
};
|
2022-02-14 22:25:36 +01:00
|
|
|
|
2022-02-11 15:15:18 +01:00
|
|
|
if (ShouldMerge()) {
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// We merge empty blocks even if the line exceeds the column limit.
|
2019-08-10 07:51:21 +00:00
|
|
|
Tok->SpacesRequiredBefore = Style.SpaceInEmptyBlock ? 1 : 0;
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
Tok->CanBreakBefore = true;
|
|
|
|
return 1;
|
2018-09-05 07:44:02 +00:00
|
|
|
} else if (Limit != 0 && !Line.startsWithNamespace() &&
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
!startsExternCBlock(Line)) {
|
|
|
|
// We don't merge short records.
|
2022-02-14 22:25:36 +01:00
|
|
|
if (isRecordLBrace(*Line.Last))
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
return 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// Check that we still have three lines and they fit into the limit.
|
|
|
|
if (I + 2 == E || I[2]->Type == LT_Invalid)
|
|
|
|
return 0;
|
|
|
|
Limit = limitConsideringMacros(I + 2, E, Limit);
|
2014-12-10 19:00:42 +00:00
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
if (!nextTwoLinesFitInto(I, Limit))
|
|
|
|
return 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// Second, check that the next line does not contain any braces - if it
|
|
|
|
// does, readability declines when putting it into a single line.
|
|
|
|
if (I[1]->Last->is(TT_LineComment))
|
2014-12-10 19:00:42 +00:00
|
|
|
return 0;
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
do {
|
2020-07-27 23:19:02 +01:00
|
|
|
if (Tok->is(tok::l_brace) && Tok->isNot(BK_BracedInit))
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
return 0;
|
|
|
|
Tok = Tok->Next;
|
|
|
|
} while (Tok);
|
2014-12-10 19:00:42 +00:00
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// Last, check that the third line starts with a closing brace.
|
|
|
|
Tok = I[2]->First;
|
|
|
|
if (Tok->isNot(tok::r_brace))
|
|
|
|
return 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// Don't merge "if (a) { .. } else {".
|
|
|
|
if (Tok->Next && Tok->Next->is(tok::kw_else))
|
|
|
|
return 0;
|
|
|
|
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
// Don't merge a trailing multi-line control statement block like:
|
|
|
|
// } else if (foo &&
|
|
|
|
// bar)
|
|
|
|
// { <-- current Line
|
|
|
|
// baz();
|
|
|
|
// }
|
2021-11-25 08:30:31 +00:00
|
|
|
if (Line.First == Line.Last && Line.First->isNot(TT_FunctionLBrace) &&
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
Style.BraceWrapping.AfterControlStatement ==
|
2022-05-21 21:51:19 -07:00
|
|
|
FormatStyle::BWACS_MultiLine) {
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
return 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
[clang-format] Add ability to wrap braces after multi-line control statements
Summary:
Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values:
* "Never": This is the default, and does not do any brace wrapping after control statements.
* "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified).
* "Always": This always wraps braces after control statements.
The first and last options are backwards-compatible with "false" and "true", respectively.
The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example:
```
if (
foo
&& bar )
{
baz();
}
```
vs.
```
if (
foo
&& bar ) {
baz();
}
```
Short control statements (1 line) do not wrap the brace to the next line, e.g.
```
if (foo) {
bar();
} else {
baz();
}
```
Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek
Reviewed By: MyDeveloperDay
Subscribers: MyDeveloperDay, cfe-commits
Patch By: mitchell-stellar
Tags: #clang-format, #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D68296
llvm-svn: 373647
2019-10-03 18:42:31 +00:00
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
} else if (I[1]->First->is(tok::l_brace)) {
|
|
|
|
if (I[1]->Last->is(TT_LineComment))
|
2015-04-30 09:24:17 +00:00
|
|
|
return 0;
|
|
|
|
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
// Check for Limit <= 2 to account for the " {".
|
|
|
|
if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(*I)))
|
|
|
|
return 0;
|
|
|
|
Limit -= 2;
|
|
|
|
unsigned MergedLines = 0;
|
2019-08-11 17:48:36 +00:00
|
|
|
if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ||
|
[clang-format] Fixed one-line if statement
Summary:
**Short overview:**
Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short blocks. Different flags combinations do not guarantee expected result. Turned on option AllowShortBlocksOnASingleLine does not work as intended.
**Description of the problem:**
Cpp source file UnwrappedLineFormatter does not handle AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control statement without any braces, clang-format works as expected (depending on AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). Putting a single-line control statement in braces, we can observe strange and incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The function returns a number of lines to be merged. Unfortunately, our control statement block is not covered properly. There are several if-return statements, but none of them handles our block. A block is identified by the line first token and by left and right braces. A function block works as expected, there is such an if-return statement doing proper job. A control statement block, from the other hand, falls into strange conditional construct, which depends on BraceWrapping.AfterFunction flag (with condition that the line’s last token is left brace, what is possible in our case) or goes even further. That should definitely not happen.
**Description of the patch:**
By adding three different if statements, we guarantee that our short control statement block, however it looks like (different brace wrapping flags may be turned on), is handled properly and does not fall into wrong conditional construct. Depending on appropriate options we return either 0 (when something disturbs our merging attempt) or let another function (tryMergeSimpleBlock) take the responsibility of returned result (number of merged lines). Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock function. The function, previously, returned either 0 or 2. The problem was that this did not handle the case when our block had the left brace in a separate line, not the header one. After change, after adding condition, we return the result compatible with block’s structure. In case of left brace in the header’s line we do everything as before the patch. In case of left brace in a separate line we do the job similar to the one we do in case of a “non-header left brace” function short block. To be precise, we try to merge the block ignoring the header line. Then, if success, we increment our returned result.
**After fix:**
**CONFIG:**
```
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Custom
BraceWrapping: {
AfterClass: true, AfterControlStatement: true, AfterEnum: true, AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: true, BeforeCatch: true, BeforeElse: true
}
```
**BEFORE:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) {
doSomething();
}
if (statement)
{
doSomething();
}
if (statement)
doSomething();
if (statement) {
doSomething1();
doSomething2();
}
```
**AFTER:**
```
if (statement) doSomething();
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) { doSomething(); }
if (statement) doSomething();
if (statement)
{
doSomething1();
doSomething2();
}
```
Contributed by @PriMee!
Reviewers: krasimir, djasper
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D37140
llvm-svn: 312904
2017-09-11 10:12:16 +00:00
|
|
|
(I[1]->First == I[1]->Last && I + 2 != E &&
|
|
|
|
I[2]->First->is(tok::r_brace))) {
|
|
|
|
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
|
|
|
|
// If we managed to merge the block, count the statement header, which
|
|
|
|
// is on a separate line.
|
|
|
|
if (MergedLines > 0)
|
|
|
|
++MergedLines;
|
|
|
|
}
|
|
|
|
return MergedLines;
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the modified column limit for \p I if it is inside a macro and
|
|
|
|
/// needs a trailing '\'.
|
|
|
|
unsigned
|
|
|
|
limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
|
|
|
|
unsigned Limit) {
|
|
|
|
if (I[0]->InPPDirective && I + 1 != E &&
|
2022-05-21 21:51:19 -07:00
|
|
|
!I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
return Limit < 2 ? 0 : Limit - 2;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
return Limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
|
|
|
unsigned Limit) {
|
|
|
|
if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
|
|
|
|
return false;
|
|
|
|
return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool containsMustBreak(const AnnotatedLine *Line) {
|
[clang-format] Ignore first token when finding MustBreak
When in ColumnLimit 0, the formatter looks for MustBreakBefore in the
line in order to check if a line is allowed to be merged onto one line.
However, since MustBreakBefore is really a property of the gap between
the token and the one previously, I belive the check is erroneous in
checking all the tokens in a line, since whether the previous line ended
with a forced line break should have no effect on whether the current
line is allowed to merge with the next one.
This patch changes the check to skip the first token in
`LineJoiner.containsMustBreak`.
This patch also changes a test, which is not ideal, but I believe the
test also suffered from this bug. The test case in question sets
AllowShortFunctionsOnASingleLine to "Empty", but the empty function in
said test case isn't merged to a single line, because of the very same
bug this patch fixes.
Fixes https://github.com/llvm/llvm-project/issues/62721
Reviewed By: HazardyKnusperkeks, owenpan, MyDeveloperDay
Differential Revision: https://reviews.llvm.org/D150614
2023-05-18 05:50:10 +03:00
|
|
|
assert(Line->First);
|
|
|
|
// Ignore the first token, because in this situation, it applies more to the
|
|
|
|
// last token of the previous line.
|
|
|
|
for (const FormatToken *Tok = Line->First->Next; Tok; Tok = Tok->Next)
|
2014-12-10 19:00:42 +00:00
|
|
|
if (Tok->MustBreakBefore)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-05-12 09:23:57 +00:00
|
|
|
void join(AnnotatedLine &A, const AnnotatedLine &B) {
|
|
|
|
assert(!A.Last->Next);
|
|
|
|
assert(!B.First->Previous);
|
|
|
|
if (B.Affected)
|
|
|
|
A.Affected = true;
|
|
|
|
A.Last->Next = B.First;
|
|
|
|
B.First->Previous = A.Last;
|
|
|
|
B.First->CanBreakBefore = true;
|
|
|
|
unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
|
|
|
|
for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
|
|
|
|
Tok->TotalLength += LengthA;
|
|
|
|
A.Last = Tok;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-10 19:00:42 +00:00
|
|
|
const FormatStyle &Style;
|
2015-02-04 15:26:27 +00:00
|
|
|
const AdditionalKeywords &Keywords;
|
2015-06-17 13:08:06 +00:00
|
|
|
const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
|
2015-05-12 09:23:57 +00:00
|
|
|
|
2015-06-17 13:08:06 +00:00
|
|
|
SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
|
2017-06-14 12:29:47 +00:00
|
|
|
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
|
2014-12-10 19:00:42 +00:00
|
|
|
};
|
|
|
|
|
2015-05-11 08:21:35 +00:00
|
|
|
static void markFinalized(FormatToken *Tok) {
|
|
|
|
for (; Tok; Tok = Tok->Next) {
|
2023-02-01 13:20:28 +00:00
|
|
|
if (Tok->MacroCtx && Tok->MacroCtx->Role == MR_ExpandedArg) {
|
|
|
|
// In the first pass we format all macro arguments in the expanded token
|
|
|
|
// stream. Instead of finalizing the macro arguments, we mark that they
|
|
|
|
// will be modified as unexpanded arguments (as part of the macro call
|
|
|
|
// formatting) in the next pass.
|
|
|
|
Tok->MacroCtx->Role = MR_UnexpandedArg;
|
|
|
|
// Reset whether spaces are required before this token, as that is context
|
|
|
|
// dependent, and that context may change when formatting the macro call.
|
|
|
|
// For example, given M(x) -> 2 * x, and the macro call M(var),
|
|
|
|
// the token 'var' will have SpacesRequiredBefore = 1 after being
|
|
|
|
// formatted as part of the expanded macro, but SpacesRequiredBefore = 0
|
|
|
|
// for its position within the macro call.
|
|
|
|
Tok->SpacesRequiredBefore = 0;
|
|
|
|
} else {
|
|
|
|
Tok->Finalized = true;
|
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
static void printLineState(const LineState &State) {
|
|
|
|
llvm::dbgs() << "State: ";
|
|
|
|
for (const ParenState &P : State.Stack) {
|
2018-05-09 09:02:11 +00:00
|
|
|
llvm::dbgs() << (P.Tok ? P.Tok->TokenText : "F") << "|" << P.Indent << "|"
|
|
|
|
<< P.LastSpace << "|" << P.NestedBlockIndent << " ";
|
2015-05-11 08:21:35 +00:00
|
|
|
}
|
|
|
|
llvm::dbgs() << State.NextToken->TokenText << "\n";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Base class for classes that format one \c AnnotatedLine.
|
2015-05-11 08:21:35 +00:00
|
|
|
class LineFormatter {
|
2014-12-10 19:00:42 +00:00
|
|
|
public:
|
2015-05-11 08:21:35 +00:00
|
|
|
LineFormatter(ContinuationIndenter *Indenter, WhitespaceManager *Whitespaces,
|
|
|
|
const FormatStyle &Style,
|
|
|
|
UnwrappedLineFormatter *BlockFormatter)
|
|
|
|
: Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
|
|
|
|
BlockFormatter(BlockFormatter) {}
|
2015-10-20 13:23:58 +00:00
|
|
|
virtual ~LineFormatter() {}
|
2015-05-11 08:21:35 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Formats an \c AnnotatedLine and returns the penalty.
|
2015-05-11 08:21:35 +00:00
|
|
|
///
|
|
|
|
/// If \p DryRun is \c false, directly applies the changes.
|
2019-03-01 09:09:54 +00:00
|
|
|
virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
|
|
|
|
unsigned FirstStartColumn, bool DryRun) = 0;
|
2015-05-11 08:21:35 +00:00
|
|
|
|
|
|
|
protected:
|
2018-05-09 01:00:01 +00:00
|
|
|
/// If the \p State's next token is an r_brace closing a nested block,
|
2015-05-11 08:21:35 +00:00
|
|
|
/// format the nested block before it.
|
|
|
|
///
|
|
|
|
/// Returns \c true if all children could be placed successfully and adapts
|
|
|
|
/// \p Penalty as well as \p State. If \p DryRun is false, also directly
|
|
|
|
/// creates changes using \c Whitespaces.
|
|
|
|
///
|
|
|
|
/// The crucial idea here is that children always get formatted upon
|
|
|
|
/// encountering the closing brace right after the nested block. Now, if we
|
|
|
|
/// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
|
|
|
|
/// \c false), the entire block has to be kept on the same line (which is only
|
|
|
|
/// possible if it fits on the line, only contains a single statement, etc.
|
|
|
|
///
|
|
|
|
/// If \p NewLine is true, we format the nested block on separate lines, i.e.
|
|
|
|
/// break after the "{", format all lines with correct indentation and the put
|
|
|
|
/// the closing "}" on yet another new line.
|
|
|
|
///
|
|
|
|
/// This enables us to keep the simple structure of the
|
|
|
|
/// \c UnwrappedLineFormatter, where we only have two options for each token:
|
|
|
|
/// break or don't break.
|
|
|
|
bool formatChildren(LineState &State, bool NewLine, bool DryRun,
|
|
|
|
unsigned &Penalty) {
|
|
|
|
const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
|
2023-02-01 13:20:28 +00:00
|
|
|
bool HasLBrace = LBrace && LBrace->is(tok::l_brace) && LBrace->is(BK_Block);
|
2015-05-11 08:21:35 +00:00
|
|
|
FormatToken &Previous = *State.NextToken->Previous;
|
2023-02-01 13:20:28 +00:00
|
|
|
if (Previous.Children.size() == 0 || (!HasLBrace && !LBrace->MacroParent)) {
|
2015-05-11 08:21:35 +00:00
|
|
|
// The previous token does not open a block. Nothing to do. We don't
|
|
|
|
// assert so that we can simply call this function for all tokens.
|
|
|
|
return true;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
|
2023-02-01 13:20:28 +00:00
|
|
|
if (NewLine || Previous.MacroParent) {
|
2021-06-22 20:39:27 +02:00
|
|
|
const ParenState &P = State.Stack.back();
|
|
|
|
|
|
|
|
int AdditionalIndent =
|
|
|
|
P.Indent - Previous.Children[0]->Level * Style.IndentWidth;
|
2015-05-11 08:21:35 +00:00
|
|
|
Penalty +=
|
|
|
|
BlockFormatter->format(Previous.Children, DryRun, AdditionalIndent,
|
|
|
|
/*FixBadIndentation=*/true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Previous.Children[0]->First->MustBreakBefore)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Cannot merge into one line if this line ends on a comment.
|
|
|
|
if (Previous.is(tok::comment))
|
|
|
|
return false;
|
|
|
|
|
2017-01-31 11:25:01 +00:00
|
|
|
// Cannot merge multiple statements into a single line.
|
|
|
|
if (Previous.Children.size() > 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const AnnotatedLine *Child = Previous.Children[0];
|
2015-05-11 08:21:35 +00:00
|
|
|
// We can't put the closing "}" on a line with a trailing comment.
|
2017-01-31 11:25:01 +00:00
|
|
|
if (Child->Last->isTrailingComment())
|
2015-05-11 08:21:35 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the child line exceeds the column limit, we wouldn't want to merge it.
|
|
|
|
// We add +2 for the trailing " }".
|
|
|
|
if (Style.ColumnLimit > 0 &&
|
2022-05-21 21:51:19 -07:00
|
|
|
Child->Last->TotalLength + State.Column + 2 > Style.ColumnLimit) {
|
2015-05-11 08:21:35 +00:00
|
|
|
return false;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
|
|
|
|
if (!DryRun) {
|
|
|
|
Whitespaces->replaceWhitespace(
|
2017-01-31 11:25:01 +00:00
|
|
|
*Child->First, /*Newlines=*/0, /*Spaces=*/1,
|
2020-04-13 15:14:26 +01:00
|
|
|
/*StartOfTokenColumn=*/State.Column, /*IsAligned=*/false,
|
|
|
|
State.Line->InPPDirective);
|
2015-05-11 08:21:35 +00:00
|
|
|
}
|
2017-10-30 14:01:50 +00:00
|
|
|
Penalty +=
|
|
|
|
formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun);
|
2015-05-11 08:21:35 +00:00
|
|
|
|
2017-01-31 11:25:01 +00:00
|
|
|
State.Column += 1 + Child->Last->TotalLength;
|
2015-05-11 08:21:35 +00:00
|
|
|
return true;
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2015-05-11 08:21:35 +00:00
|
|
|
ContinuationIndenter *Indenter;
|
|
|
|
|
|
|
|
private:
|
|
|
|
WhitespaceManager *Whitespaces;
|
|
|
|
const FormatStyle &Style;
|
|
|
|
UnwrappedLineFormatter *BlockFormatter;
|
|
|
|
};
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Formatter that keeps the existing line breaks.
|
2015-05-11 08:21:35 +00:00
|
|
|
class NoColumnLimitLineFormatter : public LineFormatter {
|
|
|
|
public:
|
|
|
|
NoColumnLimitLineFormatter(ContinuationIndenter *Indenter,
|
|
|
|
WhitespaceManager *Whitespaces,
|
|
|
|
const FormatStyle &Style,
|
|
|
|
UnwrappedLineFormatter *BlockFormatter)
|
|
|
|
: LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Formats the line, simply keeping all of the input's line breaking
|
2015-05-11 08:21:35 +00:00
|
|
|
/// decisions.
|
|
|
|
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
|
2017-10-30 14:01:50 +00:00
|
|
|
unsigned FirstStartColumn, bool DryRun) override {
|
2015-05-11 08:21:35 +00:00
|
|
|
assert(!DryRun);
|
2017-10-30 14:01:50 +00:00
|
|
|
LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn,
|
|
|
|
&Line, /*DryRun=*/false);
|
2014-12-10 19:00:42 +00:00
|
|
|
while (State.NextToken) {
|
|
|
|
bool Newline =
|
|
|
|
Indenter->mustBreak(State) ||
|
|
|
|
(Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
|
2015-04-23 09:23:17 +00:00
|
|
|
unsigned Penalty = 0;
|
2015-05-11 08:21:35 +00:00
|
|
|
formatChildren(State, Newline, /*DryRun=*/false, Penalty);
|
2014-12-10 19:00:42 +00:00
|
|
|
Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
|
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
return 0;
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
};
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Formatter that puts all tokens into a single line without breaks.
|
2015-05-11 08:21:35 +00:00
|
|
|
class NoLineBreakFormatter : public LineFormatter {
|
|
|
|
public:
|
|
|
|
NoLineBreakFormatter(ContinuationIndenter *Indenter,
|
|
|
|
WhitespaceManager *Whitespaces, const FormatStyle &Style,
|
|
|
|
UnwrappedLineFormatter *BlockFormatter)
|
|
|
|
: LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Puts all tokens into a single line.
|
2015-05-11 08:21:35 +00:00
|
|
|
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
|
2017-10-30 14:01:50 +00:00
|
|
|
unsigned FirstStartColumn, bool DryRun) override {
|
2015-05-11 08:21:35 +00:00
|
|
|
unsigned Penalty = 0;
|
2017-10-30 14:01:50 +00:00
|
|
|
LineState State =
|
|
|
|
Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
|
2015-05-11 08:21:35 +00:00
|
|
|
while (State.NextToken) {
|
2019-07-16 04:46:31 +00:00
|
|
|
formatChildren(State, /*NewLine=*/false, DryRun, Penalty);
|
2017-05-18 08:07:52 +00:00
|
|
|
Indenter->addTokenToState(
|
|
|
|
State, /*Newline=*/State.NextToken->MustBreakBefore, DryRun);
|
2015-05-11 08:21:35 +00:00
|
|
|
}
|
|
|
|
return Penalty;
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
};
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Finds the best way to break lines.
|
2015-05-11 08:21:35 +00:00
|
|
|
class OptimizingLineFormatter : public LineFormatter {
|
|
|
|
public:
|
|
|
|
OptimizingLineFormatter(ContinuationIndenter *Indenter,
|
|
|
|
WhitespaceManager *Whitespaces,
|
|
|
|
const FormatStyle &Style,
|
|
|
|
UnwrappedLineFormatter *BlockFormatter)
|
|
|
|
: LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Formats the line by finding the best line breaks with line lengths
|
2015-05-11 08:21:35 +00:00
|
|
|
/// below the column limit.
|
|
|
|
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
|
2017-10-30 14:01:50 +00:00
|
|
|
unsigned FirstStartColumn, bool DryRun) override {
|
|
|
|
LineState State =
|
|
|
|
Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
|
2015-05-11 08:21:35 +00:00
|
|
|
|
|
|
|
// If the ObjC method declaration does not fit on a line, we should format
|
|
|
|
// it with one arg per line.
|
|
|
|
if (State.Line->Type == LT_ObjCMethodDecl)
|
|
|
|
State.Stack.back().BreakBeforeParameter = true;
|
|
|
|
|
|
|
|
// Find best solution in solution space.
|
|
|
|
return analyzeSolutionSpace(State, DryRun);
|
|
|
|
}
|
2015-01-23 19:37:25 +00:00
|
|
|
|
2015-05-11 08:21:35 +00:00
|
|
|
private:
|
|
|
|
struct CompareLineStatePointers {
|
|
|
|
bool operator()(LineState *obj1, LineState *obj2) const {
|
|
|
|
return *obj1 < *obj2;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// A pair of <penalty, count> that is used to prioritize the BFS on.
|
2015-05-11 08:21:35 +00:00
|
|
|
///
|
|
|
|
/// In case of equal penalties, we want to prefer states that were inserted
|
|
|
|
/// first. During state generation we make sure that we insert states first
|
|
|
|
/// that break the line as late as possible.
|
|
|
|
typedef std::pair<unsigned, unsigned> OrderedPenalty;
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// An edge in the solution space from \c Previous->State to \c State,
|
2015-05-11 08:21:35 +00:00
|
|
|
/// inserting a newline dependent on the \c NewLine.
|
|
|
|
struct StateNode {
|
|
|
|
StateNode(const LineState &State, bool NewLine, StateNode *Previous)
|
|
|
|
: State(State), NewLine(NewLine), Previous(Previous) {}
|
|
|
|
LineState State;
|
|
|
|
bool NewLine;
|
|
|
|
StateNode *Previous;
|
|
|
|
};
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// An item in the prioritized BFS search queue. The \c StateNode's
|
2015-05-11 08:21:35 +00:00
|
|
|
/// \c State has the given \c OrderedPenalty.
|
|
|
|
typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// The BFS queue type.
|
2022-07-10 23:49:16 -07:00
|
|
|
typedef std::priority_queue<QueueItem, SmallVector<QueueItem>,
|
2017-09-20 09:51:03 +00:00
|
|
|
std::greater<QueueItem>>
|
|
|
|
QueueType;
|
2015-05-11 08:21:35 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Analyze the entire solution space starting from \p InitialState.
|
2015-05-11 08:21:35 +00:00
|
|
|
///
|
|
|
|
/// This implements a variant of Dijkstra's algorithm on the graph that spans
|
|
|
|
/// the solution space (\c LineStates are the nodes). The algorithm tries to
|
|
|
|
/// find the shortest path (the one with lowest penalty) from \p InitialState
|
|
|
|
/// to a state where all tokens are placed. Returns the penalty.
|
|
|
|
///
|
|
|
|
/// If \p DryRun is \c false, directly applies the changes.
|
|
|
|
unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun) {
|
|
|
|
std::set<LineState *, CompareLineStatePointers> Seen;
|
|
|
|
|
|
|
|
// Increasing count of \c StateNode items we have created. This is used to
|
|
|
|
// create a deterministic order independent of the container.
|
|
|
|
unsigned Count = 0;
|
|
|
|
QueueType Queue;
|
|
|
|
|
|
|
|
// Insert start element into queue.
|
2021-12-03 08:25:23 +01:00
|
|
|
StateNode *RootNode =
|
2015-05-11 08:21:35 +00:00
|
|
|
new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
|
2021-12-03 08:25:23 +01:00
|
|
|
Queue.push(QueueItem(OrderedPenalty(0, Count), RootNode));
|
2015-05-11 08:21:35 +00:00
|
|
|
++Count;
|
|
|
|
|
|
|
|
unsigned Penalty = 0;
|
|
|
|
|
|
|
|
// While not empty, take first element and follow edges.
|
|
|
|
while (!Queue.empty()) {
|
2022-06-24 22:09:57 -07:00
|
|
|
// Quit if we still haven't found a solution by now.
|
|
|
|
if (Count > 25000000)
|
|
|
|
return 0;
|
|
|
|
|
2015-05-11 08:21:35 +00:00
|
|
|
Penalty = Queue.top().first.first;
|
|
|
|
StateNode *Node = Queue.top().second;
|
|
|
|
if (!Node->State.NextToken) {
|
2018-05-15 13:30:56 +00:00
|
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
|
|
<< "\n---\nPenalty for line: " << Penalty << "\n");
|
2015-05-11 08:21:35 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Queue.pop();
|
|
|
|
|
|
|
|
// Cut off the analysis of certain solutions if the analysis gets too
|
|
|
|
// complex. See description of IgnoreStackForComparison.
|
2015-10-27 22:55:55 +00:00
|
|
|
if (Count > 50000)
|
2015-05-11 08:21:35 +00:00
|
|
|
Node->State.IgnoreStackForComparison = true;
|
|
|
|
|
2022-05-21 21:51:19 -07:00
|
|
|
if (!Seen.insert(&Node->State).second) {
|
2015-05-11 08:21:35 +00:00
|
|
|
// State already examined with lower penalty.
|
|
|
|
continue;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
|
2020-07-27 23:19:02 +01:00
|
|
|
FormatDecision LastFormat = Node->State.NextToken->getDecision();
|
2015-05-11 08:21:35 +00:00
|
|
|
if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
|
2021-12-05 12:31:56 +01:00
|
|
|
addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
|
2015-05-11 08:21:35 +00:00
|
|
|
if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
|
2021-12-05 12:31:56 +01:00
|
|
|
addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
|
2015-05-11 08:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Queue.empty()) {
|
|
|
|
// We were unable to find a solution, do nothing.
|
|
|
|
// FIXME: Add diagnostic?
|
2018-05-15 13:30:56 +00:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Could not find a solution.\n");
|
2015-05-11 08:21:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reconstruct the solution.
|
|
|
|
if (!DryRun)
|
|
|
|
reconstructPath(InitialState, Queue.top().second);
|
|
|
|
|
2018-05-15 13:30:56 +00:00
|
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
|
|
<< "Total number of analyzed states: " << Count << "\n");
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "---\n");
|
2015-05-11 08:21:35 +00:00
|
|
|
|
|
|
|
return Penalty;
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Add the following state to the analysis queue \c Queue.
|
2015-05-11 08:21:35 +00:00
|
|
|
///
|
|
|
|
/// Assume the current state is \p PreviousNode and has been reached with a
|
|
|
|
/// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
|
|
|
|
void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
|
2021-12-05 12:31:56 +01:00
|
|
|
bool NewLine, unsigned *Count, QueueType *Queue) {
|
2015-05-11 08:21:35 +00:00
|
|
|
if (NewLine && !Indenter->canBreak(PreviousNode->State))
|
|
|
|
return;
|
|
|
|
if (!NewLine && Indenter->mustBreak(PreviousNode->State))
|
|
|
|
return;
|
|
|
|
|
|
|
|
StateNode *Node = new (Allocator.Allocate())
|
|
|
|
StateNode(PreviousNode->State, NewLine, PreviousNode);
|
|
|
|
if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
|
|
|
|
return;
|
|
|
|
|
|
|
|
Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
|
|
|
|
|
2021-12-05 12:31:56 +01:00
|
|
|
Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
|
|
|
|
++(*Count);
|
2015-05-11 08:21:35 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Applies the best formatting by reconstructing the path in the
|
2015-05-11 08:21:35 +00:00
|
|
|
/// solution space that leads to \c Best.
|
|
|
|
void reconstructPath(LineState &State, StateNode *Best) {
|
2021-12-03 08:27:18 +01:00
|
|
|
llvm::SmallVector<StateNode *> Path;
|
2015-05-11 08:21:35 +00:00
|
|
|
// We do not need a break before the initial token.
|
|
|
|
while (Best->Previous) {
|
2021-12-03 08:27:18 +01:00
|
|
|
Path.push_back(Best);
|
2015-05-11 08:21:35 +00:00
|
|
|
Best = Best->Previous;
|
|
|
|
}
|
2021-12-03 08:27:18 +01:00
|
|
|
for (const auto &Node : llvm::reverse(Path)) {
|
2015-05-11 08:21:35 +00:00
|
|
|
unsigned Penalty = 0;
|
2021-12-03 08:27:18 +01:00
|
|
|
formatChildren(State, Node->NewLine, /*DryRun=*/false, Penalty);
|
|
|
|
Penalty += Indenter->addTokenToState(State, Node->NewLine, false);
|
2015-05-11 08:21:35 +00:00
|
|
|
|
2018-05-15 13:30:56 +00:00
|
|
|
LLVM_DEBUG({
|
2021-12-03 08:27:18 +01:00
|
|
|
printLineState(Node->Previous->State);
|
2022-05-21 21:51:19 -07:00
|
|
|
if (Node->NewLine) {
|
2015-05-11 08:21:35 +00:00
|
|
|
llvm::dbgs() << "Penalty for placing "
|
2021-12-03 08:27:18 +01:00
|
|
|
<< Node->Previous->State.NextToken->Tok.getName()
|
[clang-format] tweaked another case of lambda formatting
Summary:
This is done in order to improve cases where the lambda's body is moved too far to the right. Consider the following snippet with column limit set to 79:
```
void f() {
leader::MakeThisCallHere(&leader_service_,
cq_.get(),
[this, liveness](const leader::ReadRecordReq& req,
std::function<void()> done) {
logger_->HandleReadRecord(
req, resp, std::move(done));
});
leader::MakeAnother(&leader_service_,
cq_.get(),
[this, liveness](const leader::ReadRecordReq& req,
std::function<void()> done) {
logger_->HandleReadRecord(
req, resp, std::move(done), a);
});
}
```
The tool favors extra indentation for the lambda body and so the code incurs extra wrapping and adjacent calls are indented to a different level. I find this behavior annoying and I'd like the tool to favor new lines and, thus, use the extra width.
The fix, reduced, brings the following formatting.
Before:
function(1,
[] {
DoStuff();
//
},
1);
After:
function(
1,
[] {
DoStuff();
//
},
1);
Refer to the new tests in FormatTest.cpp
Contributed by oleg.smolsky!
Reviewers: djasper, klimek, krasimir
Subscribers: cfe-commits, owenpan
Tags: #clang
Differential Revision: https://reviews.llvm.org/D52676
llvm-svn: 345753
2018-10-31 17:56:57 +00:00
|
|
|
<< " on a new line: " << Penalty << "\n";
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
});
|
|
|
|
}
|
2015-01-23 19:37:25 +00:00
|
|
|
}
|
2015-05-11 08:21:35 +00:00
|
|
|
|
|
|
|
llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
|
|
|
|
};
|
2015-01-23 19:37:25 +00:00
|
|
|
|
2015-09-10 17:07:54 +00:00
|
|
|
} // anonymous namespace
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2019-03-01 09:09:54 +00:00
|
|
|
unsigned UnwrappedLineFormatter::format(
|
|
|
|
const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
|
|
|
|
int AdditionalIndent, bool FixBadIndentation, unsigned FirstStartColumn,
|
|
|
|
unsigned NextStartColumn, unsigned LastStartColumn) {
|
2015-05-12 09:23:57 +00:00
|
|
|
LineJoiner Joiner(Style, Keywords, Lines);
|
2014-12-10 19:00:42 +00:00
|
|
|
|
|
|
|
// Try to look up already computed penalty in DryRun-mode.
|
|
|
|
std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
|
|
|
|
&Lines, AdditionalIndent);
|
|
|
|
auto CacheIt = PenaltyCache.find(CacheKey);
|
|
|
|
if (DryRun && CacheIt != PenaltyCache.end())
|
|
|
|
return CacheIt->second;
|
|
|
|
|
|
|
|
assert(!Lines.empty());
|
|
|
|
unsigned Penalty = 0;
|
2015-05-12 09:23:57 +00:00
|
|
|
LevelIndentTracker IndentTracker(Style, Keywords, Lines[0]->Level,
|
|
|
|
AdditionalIndent);
|
2021-06-27 15:57:57 +01:00
|
|
|
const AnnotatedLine *PrevPrevLine = nullptr;
|
2014-12-10 19:00:42 +00:00
|
|
|
const AnnotatedLine *PreviousLine = nullptr;
|
2015-05-12 09:23:57 +00:00
|
|
|
const AnnotatedLine *NextLine = nullptr;
|
2015-11-01 00:27:35 +00:00
|
|
|
|
|
|
|
// The minimum level of consecutive lines that have been formatted.
|
|
|
|
unsigned RangeMinLevel = UINT_MAX;
|
|
|
|
|
2017-10-30 14:01:50 +00:00
|
|
|
bool FirstLine = true;
|
2015-05-12 09:23:57 +00:00
|
|
|
for (const AnnotatedLine *Line =
|
|
|
|
Joiner.getNextMergedLine(DryRun, IndentTracker);
|
2022-01-03 07:57:54 +01:00
|
|
|
Line; PrevPrevLine = PreviousLine, PreviousLine = Line, Line = NextLine,
|
|
|
|
FirstLine = false) {
|
2022-01-24 08:48:14 +01:00
|
|
|
assert(Line->First);
|
2015-05-12 09:23:57 +00:00
|
|
|
const AnnotatedLine &TheLine = *Line;
|
|
|
|
unsigned Indent = IndentTracker.getIndent();
|
2015-11-01 00:27:35 +00:00
|
|
|
|
|
|
|
// We continue formatting unchanged lines to adjust their indent, e.g. if a
|
|
|
|
// scope was added. However, we need to carefully stop doing this when we
|
2022-08-28 15:15:20 +08:00
|
|
|
// exit the scope of affected lines to prevent indenting the entire
|
2015-11-01 00:27:35 +00:00
|
|
|
// remaining file if it currently missing a closing brace.
|
2018-04-23 09:34:26 +00:00
|
|
|
bool PreviousRBrace =
|
|
|
|
PreviousLine && PreviousLine->startsWith(tok::r_brace);
|
2015-11-01 00:27:35 +00:00
|
|
|
bool ContinueFormatting =
|
|
|
|
TheLine.Level > RangeMinLevel ||
|
2018-04-23 09:34:26 +00:00
|
|
|
(TheLine.Level == RangeMinLevel && !PreviousRBrace &&
|
|
|
|
!TheLine.startsWith(tok::r_brace));
|
2015-11-01 00:27:35 +00:00
|
|
|
|
|
|
|
bool FixIndentation = (FixBadIndentation || ContinueFormatting) &&
|
2015-10-28 01:08:22 +00:00
|
|
|
Indent != TheLine.First->OriginalColumn;
|
2015-05-07 12:26:30 +00:00
|
|
|
bool ShouldFormat = TheLine.Affected || FixIndentation;
|
2015-05-12 09:23:57 +00:00
|
|
|
// We cannot format this line; if the reason is that the line had a
|
|
|
|
// parsing error, remember that.
|
2017-04-21 14:35:20 +00:00
|
|
|
if (ShouldFormat && TheLine.Type == LT_Invalid && Status) {
|
|
|
|
Status->FormatComplete = false;
|
|
|
|
Status->Line =
|
|
|
|
SourceMgr.getSpellingLineNumber(TheLine.First->Tok.getLocation());
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2015-05-12 09:23:57 +00:00
|
|
|
if (ShouldFormat && TheLine.Type != LT_Invalid) {
|
2017-10-30 14:01:50 +00:00
|
|
|
if (!DryRun) {
|
2022-01-24 08:48:14 +01:00
|
|
|
bool LastLine = TheLine.First->is(tok::eof);
|
2021-06-27 15:57:57 +01:00
|
|
|
formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, Indent,
|
2017-10-30 14:01:50 +00:00
|
|
|
LastLine ? LastStartColumn : NextStartColumn + Indent);
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2015-05-12 09:23:57 +00:00
|
|
|
NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
|
|
|
|
unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
|
|
|
|
bool FitsIntoOneLine =
|
2023-02-01 13:20:28 +00:00
|
|
|
!TheLine.ContainsMacroCall &&
|
|
|
|
(TheLine.Last->TotalLength + Indent <= ColumnLimit ||
|
|
|
|
(TheLine.Type == LT_ImportStatement &&
|
|
|
|
(!Style.isJavaScript() || !Style.JavaScriptWrapImports)) ||
|
|
|
|
(Style.isCSharp() &&
|
|
|
|
TheLine.InPPDirective)); // don't split #regions in C#
|
2022-05-21 21:51:19 -07:00
|
|
|
if (Style.ColumnLimit == 0) {
|
2015-05-11 08:21:35 +00:00
|
|
|
NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
|
2017-10-30 14:01:50 +00:00
|
|
|
.formatLine(TheLine, NextStartColumn + Indent,
|
|
|
|
FirstLine ? FirstStartColumn : 0, DryRun);
|
2022-05-21 21:51:19 -07:00
|
|
|
} else if (FitsIntoOneLine) {
|
2015-05-12 09:23:57 +00:00
|
|
|
Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style, this)
|
2017-10-30 14:01:50 +00:00
|
|
|
.formatLine(TheLine, NextStartColumn + Indent,
|
|
|
|
FirstLine ? FirstStartColumn : 0, DryRun);
|
2022-05-21 21:51:19 -07:00
|
|
|
} else {
|
2015-05-11 08:21:35 +00:00
|
|
|
Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style, this)
|
2017-10-30 14:01:50 +00:00
|
|
|
.formatLine(TheLine, NextStartColumn + Indent,
|
|
|
|
FirstLine ? FirstStartColumn : 0, DryRun);
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-11-01 00:27:35 +00:00
|
|
|
RangeMinLevel = std::min(RangeMinLevel, TheLine.Level);
|
2014-12-10 19:00:42 +00:00
|
|
|
} else {
|
2015-05-12 09:23:57 +00:00
|
|
|
// If no token in the current line is affected, we still need to format
|
|
|
|
// affected children.
|
2022-05-21 21:51:19 -07:00
|
|
|
if (TheLine.ChildrenAffected) {
|
2016-02-29 12:26:20 +00:00
|
|
|
for (const FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next)
|
|
|
|
if (!Tok->Children.empty())
|
|
|
|
format(Tok->Children, DryRun);
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-12 09:23:57 +00:00
|
|
|
|
|
|
|
// Adapt following lines on the current indent level to the same level
|
|
|
|
// unless the current \c AnnotatedLine is not at the beginning of a line.
|
|
|
|
bool StartsNewLine =
|
|
|
|
TheLine.First->NewlinesBefore > 0 || TheLine.First->IsFirst;
|
|
|
|
if (StartsNewLine)
|
|
|
|
IndentTracker.adjustToUnmodifiedLine(TheLine);
|
|
|
|
if (!DryRun) {
|
|
|
|
bool ReformatLeadingWhitespace =
|
|
|
|
StartsNewLine && ((PreviousLine && PreviousLine->Affected) ||
|
|
|
|
TheLine.LeadingEmptyLinesAffected);
|
|
|
|
// Format the first token.
|
2022-05-21 21:51:19 -07:00
|
|
|
if (ReformatLeadingWhitespace) {
|
2021-06-27 15:57:57 +01:00
|
|
|
formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines,
|
2017-10-30 14:01:50 +00:00
|
|
|
TheLine.First->OriginalColumn,
|
2017-01-31 11:25:01 +00:00
|
|
|
TheLine.First->OriginalColumn);
|
2022-05-21 21:51:19 -07:00
|
|
|
} else {
|
2015-05-12 09:23:57 +00:00
|
|
|
Whitespaces->addUntouchableToken(*TheLine.First,
|
|
|
|
TheLine.InPPDirective);
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2015-05-12 09:23:57 +00:00
|
|
|
|
|
|
|
// Notify the WhitespaceManager about the unchanged whitespace.
|
|
|
|
for (FormatToken *Tok = TheLine.First->Next; Tok; Tok = Tok->Next)
|
2014-12-10 19:00:42 +00:00
|
|
|
Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
|
|
|
|
}
|
2015-05-12 09:23:57 +00:00
|
|
|
NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
|
2015-11-01 00:27:35 +00:00
|
|
|
RangeMinLevel = UINT_MAX;
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
2023-06-18 23:18:00 -07:00
|
|
|
if (!DryRun) {
|
|
|
|
auto *Tok = TheLine.First;
|
|
|
|
if (Tok->is(tok::hash) && !Tok->Previous && Tok->Next &&
|
|
|
|
Tok->Next->isOneOf(tok::pp_if, tok::pp_ifdef, tok::pp_ifndef,
|
|
|
|
tok::pp_elif, tok::pp_elifdef, tok::pp_elifndef,
|
|
|
|
tok::pp_else, tok::pp_endif)) {
|
|
|
|
Tok = Tok->Next;
|
|
|
|
}
|
|
|
|
markFinalized(Tok);
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
|
|
|
PenaltyCache[CacheKey] = Penalty;
|
|
|
|
return Penalty;
|
|
|
|
}
|
|
|
|
|
2023-06-14 15:06:17 -07:00
|
|
|
static auto computeNewlines(const AnnotatedLine &Line,
|
|
|
|
const AnnotatedLine *PreviousLine,
|
|
|
|
const AnnotatedLine *PrevPrevLine,
|
|
|
|
const SmallVectorImpl<AnnotatedLine *> &Lines,
|
|
|
|
const FormatStyle &Style) {
|
|
|
|
const auto &RootToken = *Line.First;
|
|
|
|
auto Newlines =
|
2014-12-10 19:00:42 +00:00
|
|
|
std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
|
|
|
|
// Remove empty lines before "}" where applicable.
|
|
|
|
if (RootToken.is(tok::r_brace) &&
|
|
|
|
(!RootToken.Next ||
|
2018-04-19 13:02:15 +00:00
|
|
|
(RootToken.Next->is(tok::semi) && !RootToken.Next->Next)) &&
|
|
|
|
// Do not remove empty lines before namespace closing "}".
|
2022-05-21 21:51:19 -07:00
|
|
|
!getNamespaceToken(&Line, Lines)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
Newlines = std::min(Newlines, 1u);
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2017-11-17 18:06:33 +00:00
|
|
|
// Remove empty lines at the start of nested blocks (lambdas/arrow functions)
|
2023-02-19 16:05:55 -08:00
|
|
|
if (!PreviousLine && Line.Level > 0)
|
2017-11-17 18:06:33 +00:00
|
|
|
Newlines = std::min(Newlines, 1u);
|
2014-12-10 19:00:42 +00:00
|
|
|
if (Newlines == 0 && !RootToken.IsFirst)
|
|
|
|
Newlines = 1;
|
|
|
|
if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
|
|
|
|
Newlines = 0;
|
|
|
|
|
|
|
|
// Remove empty lines after "{".
|
|
|
|
if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
|
|
|
|
PreviousLine->Last->is(tok::l_brace) &&
|
2018-09-05 07:44:02 +00:00
|
|
|
!PreviousLine->startsWithNamespace() &&
|
2021-06-27 15:57:57 +01:00
|
|
|
!(PrevPrevLine && PrevPrevLine->startsWithNamespace() &&
|
|
|
|
PreviousLine->startsWith(tok::l_brace)) &&
|
2022-05-21 21:51:19 -07:00
|
|
|
!startsExternCBlock(*PreviousLine)) {
|
2014-12-10 19:00:42 +00:00
|
|
|
Newlines = 1;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2021-01-25 20:47:22 +01:00
|
|
|
// Insert or remove empty line before access specifiers.
|
|
|
|
if (PreviousLine && RootToken.isAccessSpecifier()) {
|
|
|
|
switch (Style.EmptyLineBeforeAccessModifier) {
|
|
|
|
case FormatStyle::ELBAMS_Never:
|
2021-04-16 10:02:02 +02:00
|
|
|
if (Newlines > 1)
|
2021-01-25 20:47:22 +01:00
|
|
|
Newlines = 1;
|
|
|
|
break;
|
|
|
|
case FormatStyle::ELBAMS_Leave:
|
|
|
|
Newlines = std::max(RootToken.NewlinesBefore, 1u);
|
|
|
|
break;
|
|
|
|
case FormatStyle::ELBAMS_LogicalBlock:
|
2021-04-16 10:02:02 +02:00
|
|
|
if (PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) && Newlines <= 1)
|
2021-01-25 20:47:22 +01:00
|
|
|
Newlines = 2;
|
2021-04-15 17:27:20 +02:00
|
|
|
if (PreviousLine->First->isAccessSpecifier())
|
|
|
|
Newlines = 1; // Previous is an access modifier remove all new lines.
|
2021-01-25 20:47:22 +01:00
|
|
|
break;
|
|
|
|
case FormatStyle::ELBAMS_Always: {
|
|
|
|
const FormatToken *previousToken;
|
|
|
|
if (PreviousLine->Last->is(tok::comment))
|
|
|
|
previousToken = PreviousLine->Last->getPreviousNonComment();
|
|
|
|
else
|
|
|
|
previousToken = PreviousLine->Last;
|
2021-04-16 10:02:02 +02:00
|
|
|
if ((!previousToken || !previousToken->is(tok::l_brace)) && Newlines <= 1)
|
2021-01-25 20:47:22 +01:00
|
|
|
Newlines = 2;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2021-04-15 17:27:20 +02:00
|
|
|
// Insert or remove empty line after access specifiers.
|
2015-03-09 08:13:55 +00:00
|
|
|
if (PreviousLine && PreviousLine->First->isAccessSpecifier() &&
|
2021-04-15 17:27:20 +02:00
|
|
|
(!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline)) {
|
|
|
|
// EmptyLineBeforeAccessModifier is handling the case when two access
|
|
|
|
// modifiers follow each other.
|
|
|
|
if (!RootToken.isAccessSpecifier()) {
|
|
|
|
switch (Style.EmptyLineAfterAccessModifier) {
|
|
|
|
case FormatStyle::ELAAMS_Never:
|
|
|
|
Newlines = 1;
|
|
|
|
break;
|
|
|
|
case FormatStyle::ELAAMS_Leave:
|
|
|
|
Newlines = std::max(Newlines, 1u);
|
|
|
|
break;
|
|
|
|
case FormatStyle::ELAAMS_Always:
|
|
|
|
if (RootToken.is(tok::r_brace)) // Do not add at end of class.
|
|
|
|
Newlines = 1u;
|
|
|
|
else
|
|
|
|
Newlines = std::max(Newlines, 2u);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-10 19:00:42 +00:00
|
|
|
|
2023-06-14 15:06:17 -07:00
|
|
|
return Newlines;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineFormatter::formatFirstToken(
|
|
|
|
const AnnotatedLine &Line, const AnnotatedLine *PreviousLine,
|
|
|
|
const AnnotatedLine *PrevPrevLine,
|
|
|
|
const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent,
|
|
|
|
unsigned NewlineIndent) {
|
|
|
|
FormatToken &RootToken = *Line.First;
|
|
|
|
if (RootToken.is(tok::eof)) {
|
|
|
|
unsigned Newlines =
|
|
|
|
std::min(RootToken.NewlinesBefore,
|
|
|
|
Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1);
|
|
|
|
unsigned TokenIndent = Newlines ? NewlineIndent : 0;
|
|
|
|
Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
|
|
|
|
TokenIndent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RootToken.Newlines < 0) {
|
|
|
|
RootToken.Newlines =
|
|
|
|
computeNewlines(Line, PreviousLine, PrevPrevLine, Lines, Style);
|
|
|
|
assert(RootToken.Newlines >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RootToken.Newlines > 0)
|
2017-10-30 14:01:50 +00:00
|
|
|
Indent = NewlineIndent;
|
|
|
|
|
2022-03-30 23:17:27 +00:00
|
|
|
// Preprocessor directives get indented before the hash only if specified. In
|
|
|
|
// Javascript import statements are indented like normal statements.
|
|
|
|
if (!Style.isJavaScript() &&
|
|
|
|
Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
|
2021-01-17 11:07:31 +00:00
|
|
|
(Line.Type == LT_PreprocessorDirective ||
|
2022-05-21 21:51:19 -07:00
|
|
|
Line.Type == LT_ImportStatement)) {
|
2021-01-17 11:07:31 +00:00
|
|
|
Indent = 0;
|
2022-05-21 21:51:19 -07:00
|
|
|
}
|
2017-10-30 14:01:50 +00:00
|
|
|
|
2023-06-14 15:06:17 -07:00
|
|
|
Whitespaces->replaceWhitespace(RootToken, RootToken.Newlines, Indent, Indent,
|
2020-04-13 15:14:26 +01:00
|
|
|
/*IsAligned=*/false,
|
2017-01-31 11:25:01 +00:00
|
|
|
Line.InPPDirective &&
|
|
|
|
!RootToken.HasUnescapedNewline);
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 09:23:57 +00:00
|
|
|
unsigned
|
|
|
|
UnwrappedLineFormatter::getColumnLimit(bool InPPDirective,
|
|
|
|
const AnnotatedLine *NextLine) const {
|
|
|
|
// In preprocessor directives reserve two chars for trailing " \" if the
|
|
|
|
// next line continues the preprocessor directive.
|
|
|
|
bool ContinuesPPDirective =
|
2015-05-26 07:03:42 +00:00
|
|
|
InPPDirective &&
|
|
|
|
// If there is no next line, this is likely a child line and the parent
|
|
|
|
// continues the preprocessor directive.
|
|
|
|
(!NextLine ||
|
|
|
|
(NextLine->InPPDirective &&
|
|
|
|
// If there is an unescaped newline between this line and the next, the
|
|
|
|
// next line starts a new preprocessor directive.
|
|
|
|
!NextLine->First->HasUnescapedNewline));
|
2015-05-12 09:23:57 +00:00
|
|
|
return Style.ColumnLimit - (ContinuesPPDirective ? 2 : 0);
|
2014-12-10 19:00:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace format
|
|
|
|
} // namespace clang
|