2012-12-04 02:12:45 +08:00
|
|
|
//===--- UnwrappedLineParser.cpp - Format C++ code ------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08: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
|
2012-12-04 02:12:45 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
2018-05-09 09:00:01 +08:00
|
|
|
/// This file contains the implementation of the UnwrappedLineParser,
|
2012-12-04 02:12:45 +08:00
|
|
|
/// which turns a stream of tokens into UnwrappedLines.
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-01-19 16:09:44 +08:00
|
|
|
#include "UnwrappedLineParser.h"
|
2020-04-28 21:11:09 +08:00
|
|
|
#include "FormatToken.h"
|
2015-03-02 05:36:40 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2013-01-16 20:31:12 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2015-03-24 02:05:43 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-04 02:12:45 +08:00
|
|
|
|
2017-11-25 17:19:42 +08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2014-04-22 11:17:02 +08:00
|
|
|
#define DEBUG_TYPE "format-parser"
|
|
|
|
|
2012-12-04 02:12:45 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace format {
|
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
class FormatTokenSource {
|
|
|
|
public:
|
2015-10-20 21:23:58 +08:00
|
|
|
virtual ~FormatTokenSource() {}
|
2013-05-28 19:55:06 +08:00
|
|
|
virtual FormatToken *getNextToken() = 0;
|
|
|
|
|
|
|
|
virtual unsigned getPosition() = 0;
|
|
|
|
virtual FormatToken *setPosition(unsigned Position) = 0;
|
|
|
|
};
|
|
|
|
|
2013-07-01 12:21:54 +08:00
|
|
|
namespace {
|
|
|
|
|
2013-01-23 17:32:48 +08:00
|
|
|
class ScopedDeclarationState {
|
|
|
|
public:
|
|
|
|
ScopedDeclarationState(UnwrappedLine &Line, std::vector<bool> &Stack,
|
|
|
|
bool MustBeDeclaration)
|
|
|
|
: Line(Line), Stack(Stack) {
|
|
|
|
Line.MustBeDeclaration = MustBeDeclaration;
|
2013-01-23 19:03:04 +08:00
|
|
|
Stack.push_back(MustBeDeclaration);
|
2013-01-23 17:32:48 +08:00
|
|
|
}
|
|
|
|
~ScopedDeclarationState() {
|
|
|
|
Stack.pop_back();
|
2013-01-23 22:08:21 +08:00
|
|
|
if (!Stack.empty())
|
|
|
|
Line.MustBeDeclaration = Stack.back();
|
|
|
|
else
|
|
|
|
Line.MustBeDeclaration = true;
|
2013-01-23 17:32:48 +08:00
|
|
|
}
|
2013-05-31 22:56:29 +08:00
|
|
|
|
2013-01-23 17:32:48 +08:00
|
|
|
private:
|
|
|
|
UnwrappedLine &Line;
|
|
|
|
std::vector<bool> &Stack;
|
|
|
|
};
|
|
|
|
|
2017-05-19 18:34:57 +08:00
|
|
|
static bool isLineComment(const FormatToken &FormatTok) {
|
2017-11-10 20:50:09 +08:00
|
|
|
return FormatTok.is(tok::comment) && !FormatTok.TokenText.startswith("/*");
|
2017-05-19 18:34:57 +08:00
|
|
|
}
|
|
|
|
|
2017-05-22 18:07:56 +08:00
|
|
|
// Checks if \p FormatTok is a line comment that continues the line comment
|
|
|
|
// \p Previous. The original column of \p MinColumnToken is used to determine
|
|
|
|
// whether \p FormatTok is indented enough to the right to continue \p Previous.
|
|
|
|
static bool continuesLineComment(const FormatToken &FormatTok,
|
|
|
|
const FormatToken *Previous,
|
|
|
|
const FormatToken *MinColumnToken) {
|
|
|
|
if (!Previous || !MinColumnToken)
|
|
|
|
return false;
|
|
|
|
unsigned MinContinueColumn =
|
|
|
|
MinColumnToken->OriginalColumn + (isLineComment(*MinColumnToken) ? 0 : 1);
|
|
|
|
return isLineComment(FormatTok) && FormatTok.NewlinesBefore == 1 &&
|
|
|
|
isLineComment(*Previous) &&
|
|
|
|
FormatTok.OriginalColumn >= MinContinueColumn;
|
|
|
|
}
|
|
|
|
|
2013-01-05 07:34:14 +08:00
|
|
|
class ScopedMacroState : public FormatTokenSource {
|
|
|
|
public:
|
|
|
|
ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
|
2015-05-06 19:56:29 +08:00
|
|
|
FormatToken *&ResetToken)
|
2013-01-05 07:34:14 +08:00
|
|
|
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
|
2013-04-12 22:13:36 +08:00
|
|
|
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
|
2017-05-19 18:34:57 +08:00
|
|
|
Token(nullptr), PreviousToken(nullptr) {
|
2018-06-15 14:08:54 +08:00
|
|
|
FakeEOF.Tok.startToken();
|
|
|
|
FakeEOF.Tok.setKind(tok::eof);
|
2013-01-05 07:34:14 +08:00
|
|
|
TokenSource = this;
|
2013-01-06 06:14:16 +08:00
|
|
|
Line.Level = 0;
|
2013-01-05 07:34:14 +08:00
|
|
|
Line.InPPDirective = true;
|
|
|
|
}
|
|
|
|
|
2015-04-11 10:00:23 +08:00
|
|
|
~ScopedMacroState() override {
|
2013-01-05 07:34:14 +08:00
|
|
|
TokenSource = PreviousTokenSource;
|
|
|
|
ResetToken = Token;
|
|
|
|
Line.InPPDirective = false;
|
2013-01-06 06:14:16 +08:00
|
|
|
Line.Level = PreviousLineLevel;
|
2013-01-05 07:34:14 +08:00
|
|
|
}
|
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
FormatToken *getNextToken() override {
|
2013-01-07 18:03:37 +08:00
|
|
|
// The \c UnwrappedLineParser guards against this by never calling
|
|
|
|
// \c getNextToken() after it has encountered the first eof token.
|
|
|
|
assert(!eof());
|
2017-05-19 18:34:57 +08:00
|
|
|
PreviousToken = Token;
|
2013-01-05 07:34:14 +08:00
|
|
|
Token = PreviousTokenSource->getNextToken();
|
|
|
|
if (eof())
|
2018-06-15 14:08:54 +08:00
|
|
|
return &FakeEOF;
|
2013-01-05 07:34:14 +08:00
|
|
|
return Token;
|
|
|
|
}
|
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
|
2013-05-23 17:41:43 +08:00
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
FormatToken *setPosition(unsigned Position) override {
|
2017-05-19 18:34:57 +08:00
|
|
|
PreviousToken = nullptr;
|
2013-05-23 17:41:43 +08:00
|
|
|
Token = PreviousTokenSource->setPosition(Position);
|
|
|
|
return Token;
|
|
|
|
}
|
|
|
|
|
2013-01-05 07:34:14 +08:00
|
|
|
private:
|
2017-05-19 18:34:57 +08:00
|
|
|
bool eof() {
|
|
|
|
return Token && Token->HasUnescapedNewline &&
|
2017-05-22 18:07:56 +08:00
|
|
|
!continuesLineComment(*Token, PreviousToken,
|
|
|
|
/*MinColumnToken=*/PreviousToken);
|
2017-05-19 18:34:57 +08:00
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
|
2018-06-15 14:08:54 +08:00
|
|
|
FormatToken FakeEOF;
|
2013-01-05 07:34:14 +08:00
|
|
|
UnwrappedLine &Line;
|
|
|
|
FormatTokenSource *&TokenSource;
|
2013-05-28 19:55:06 +08:00
|
|
|
FormatToken *&ResetToken;
|
2013-01-06 06:14:16 +08:00
|
|
|
unsigned PreviousLineLevel;
|
2013-01-05 07:34:14 +08:00
|
|
|
FormatTokenSource *PreviousTokenSource;
|
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
FormatToken *Token;
|
2017-05-19 18:34:57 +08:00
|
|
|
FormatToken *PreviousToken;
|
2013-01-05 07:34:14 +08:00
|
|
|
};
|
|
|
|
|
2013-07-01 12:21:54 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2013-01-10 19:52:21 +08:00
|
|
|
class ScopedLineState {
|
|
|
|
public:
|
2013-01-18 22:04:34 +08:00
|
|
|
ScopedLineState(UnwrappedLineParser &Parser,
|
|
|
|
bool SwitchToPreprocessorLines = false)
|
2014-08-10 04:02:07 +08:00
|
|
|
: Parser(Parser), OriginalLines(Parser.CurrentLines) {
|
2013-01-18 22:04:34 +08:00
|
|
|
if (SwitchToPreprocessorLines)
|
|
|
|
Parser.CurrentLines = &Parser.PreprocessorDirectives;
|
2013-09-05 17:29:45 +08:00
|
|
|
else if (!Parser.Line->Tokens.empty())
|
|
|
|
Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
|
2014-08-10 04:02:07 +08:00
|
|
|
PreBlockLine = std::move(Parser.Line);
|
2019-08-15 07:04:18 +08:00
|
|
|
Parser.Line = std::make_unique<UnwrappedLine>();
|
2013-01-16 17:10:19 +08:00
|
|
|
Parser.Line->Level = PreBlockLine->Level;
|
|
|
|
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
|
2013-01-10 19:52:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~ScopedLineState() {
|
2013-01-16 17:10:19 +08:00
|
|
|
if (!Parser.Line->Tokens.empty()) {
|
2013-01-10 19:52:21 +08:00
|
|
|
Parser.addUnwrappedLine();
|
|
|
|
}
|
2013-01-16 17:10:19 +08:00
|
|
|
assert(Parser.Line->Tokens.empty());
|
2014-08-10 04:02:07 +08:00
|
|
|
Parser.Line = std::move(PreBlockLine);
|
2013-09-05 17:29:45 +08:00
|
|
|
if (Parser.CurrentLines == &Parser.PreprocessorDirectives)
|
|
|
|
Parser.MustBreakBeforeNextToken = true;
|
|
|
|
Parser.CurrentLines = OriginalLines;
|
2013-01-10 19:52:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
UnwrappedLineParser &Parser;
|
|
|
|
|
2014-08-10 04:02:07 +08:00
|
|
|
std::unique_ptr<UnwrappedLine> PreBlockLine;
|
2013-09-05 17:29:45 +08:00
|
|
|
SmallVectorImpl<UnwrappedLine> *OriginalLines;
|
2013-01-10 19:52:21 +08:00
|
|
|
};
|
|
|
|
|
2013-12-12 17:49:52 +08:00
|
|
|
class CompoundStatementIndenter {
|
|
|
|
public:
|
|
|
|
CompoundStatementIndenter(UnwrappedLineParser *Parser,
|
|
|
|
const FormatStyle &Style, unsigned &LineLevel)
|
2019-04-09 07:36:25 +08:00
|
|
|
: CompoundStatementIndenter(Parser, LineLevel,
|
|
|
|
Style.BraceWrapping.AfterControlStatement,
|
2019-07-29 21:26:48 +08:00
|
|
|
Style.BraceWrapping.IndentBraces) {}
|
2019-04-09 07:36:25 +08:00
|
|
|
CompoundStatementIndenter(UnwrappedLineParser *Parser, unsigned &LineLevel,
|
|
|
|
bool WrapBrace, bool IndentBrace)
|
2013-12-12 17:49:52 +08:00
|
|
|
: LineLevel(LineLevel), OldLineLevel(LineLevel) {
|
2019-04-09 07:36:25 +08:00
|
|
|
if (WrapBrace)
|
2013-12-12 17:49:52 +08:00
|
|
|
Parser->addUnwrappedLine();
|
2019-04-09 07:36:25 +08:00
|
|
|
if (IndentBrace)
|
2013-12-12 17:49:52 +08:00
|
|
|
++LineLevel;
|
|
|
|
}
|
2014-05-09 21:11:16 +08:00
|
|
|
~CompoundStatementIndenter() { LineLevel = OldLineLevel; }
|
2013-12-12 17:49:52 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned &LineLevel;
|
|
|
|
unsigned OldLineLevel;
|
|
|
|
};
|
|
|
|
|
2013-07-01 12:21:54 +08:00
|
|
|
namespace {
|
|
|
|
|
2013-05-23 17:41:43 +08:00
|
|
|
class IndexedTokenSource : public FormatTokenSource {
|
|
|
|
public:
|
2013-05-28 19:55:06 +08:00
|
|
|
IndexedTokenSource(ArrayRef<FormatToken *> Tokens)
|
2013-05-23 17:41:43 +08:00
|
|
|
: Tokens(Tokens), Position(-1) {}
|
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
FormatToken *getNextToken() override {
|
2013-05-23 17:41:43 +08:00
|
|
|
++Position;
|
|
|
|
return Tokens[Position];
|
|
|
|
}
|
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
unsigned getPosition() override {
|
2013-05-23 17:41:43 +08:00
|
|
|
assert(Position >= 0);
|
|
|
|
return Position;
|
|
|
|
}
|
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
FormatToken *setPosition(unsigned P) override {
|
2013-05-23 17:41:43 +08:00
|
|
|
Position = P;
|
|
|
|
return Tokens[Position];
|
|
|
|
}
|
|
|
|
|
2013-10-12 05:25:45 +08:00
|
|
|
void reset() { Position = -1; }
|
|
|
|
|
2013-05-23 17:41:43 +08:00
|
|
|
private:
|
2013-05-28 19:55:06 +08:00
|
|
|
ArrayRef<FormatToken *> Tokens;
|
2013-05-23 17:41:43 +08:00
|
|
|
int Position;
|
|
|
|
};
|
|
|
|
|
2013-07-01 12:21:54 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2013-05-15 16:14:19 +08:00
|
|
|
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
|
2014-11-04 20:41:02 +08:00
|
|
|
const AdditionalKeywords &Keywords,
|
2017-10-30 22:01:50 +08:00
|
|
|
unsigned FirstStartColumn,
|
2013-05-28 19:55:06 +08:00
|
|
|
ArrayRef<FormatToken *> Tokens,
|
2013-05-15 16:14:19 +08:00
|
|
|
UnwrappedLineConsumer &Callback)
|
2014-05-09 21:11:16 +08:00
|
|
|
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
|
2017-02-02 23:32:19 +08:00
|
|
|
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
|
|
|
|
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
|
2018-02-05 23:59:00 +08:00
|
|
|
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
|
|
|
|
? IG_Rejected
|
|
|
|
: IG_Inited),
|
|
|
|
IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn) {}
|
2013-10-12 05:25:45 +08:00
|
|
|
|
|
|
|
void UnwrappedLineParser::reset() {
|
|
|
|
PPBranchLevel = -1;
|
2018-02-05 23:59:00 +08:00
|
|
|
IncludeGuard = Style.IndentPPDirectives == FormatStyle::PPDIS_None
|
|
|
|
? IG_Rejected
|
|
|
|
: IG_Inited;
|
|
|
|
IncludeGuardToken = nullptr;
|
2013-10-12 05:25:45 +08:00
|
|
|
Line.reset(new UnwrappedLine);
|
|
|
|
CommentsBeforeNextToken.clear();
|
2014-05-09 16:15:10 +08:00
|
|
|
FormatTok = nullptr;
|
2013-10-12 05:25:45 +08:00
|
|
|
MustBreakBeforeNextToken = false;
|
|
|
|
PreprocessorDirectives.clear();
|
|
|
|
CurrentLines = &Lines;
|
|
|
|
DeclarationScopeStack.clear();
|
|
|
|
PPStack.clear();
|
2017-10-30 22:01:50 +08:00
|
|
|
Line->FirstStartColumn = FirstStartColumn;
|
2013-10-12 05:25:45 +08:00
|
|
|
}
|
2012-12-04 02:12:45 +08:00
|
|
|
|
2015-05-06 19:56:29 +08:00
|
|
|
void UnwrappedLineParser::parse() {
|
2013-05-23 17:41:43 +08:00
|
|
|
IndexedTokenSource TokenSource(AllTokens);
|
2017-10-30 22:01:50 +08:00
|
|
|
Line->FirstStartColumn = FirstStartColumn;
|
2013-10-12 05:25:45 +08:00
|
|
|
do {
|
2018-05-15 21:30:56 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "----\n");
|
2013-10-12 05:25:45 +08:00
|
|
|
reset();
|
|
|
|
Tokens = &TokenSource;
|
|
|
|
TokenSource.reset();
|
|
|
|
|
|
|
|
readToken();
|
|
|
|
parseFile();
|
2018-02-05 23:59:00 +08:00
|
|
|
|
|
|
|
// If we found an include guard then all preprocessor directives (other than
|
|
|
|
// the guard) are over-indented by one.
|
|
|
|
if (IncludeGuard == IG_Found)
|
|
|
|
for (auto &Line : Lines)
|
|
|
|
if (Line.InPPDirective && Line.Level > 0)
|
|
|
|
--Line.Level;
|
|
|
|
|
2013-10-12 05:25:45 +08:00
|
|
|
// Create line with eof token.
|
|
|
|
pushToken(FormatTok);
|
|
|
|
addUnwrappedLine();
|
|
|
|
|
|
|
|
for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(),
|
|
|
|
E = Lines.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Callback.consumeUnwrappedLine(*I);
|
|
|
|
}
|
|
|
|
Callback.finishRun();
|
|
|
|
Lines.clear();
|
|
|
|
while (!PPLevelBranchIndex.empty() &&
|
2013-10-12 21:32:56 +08:00
|
|
|
PPLevelBranchIndex.back() + 1 >= PPLevelBranchCount.back()) {
|
2013-10-12 05:25:45 +08:00
|
|
|
PPLevelBranchIndex.resize(PPLevelBranchIndex.size() - 1);
|
|
|
|
PPLevelBranchCount.resize(PPLevelBranchCount.size() - 1);
|
|
|
|
}
|
|
|
|
if (!PPLevelBranchIndex.empty()) {
|
|
|
|
++PPLevelBranchIndex.back();
|
|
|
|
assert(PPLevelBranchIndex.size() == PPLevelBranchCount.size());
|
|
|
|
assert(PPLevelBranchIndex.back() <= PPLevelBranchCount.back());
|
|
|
|
}
|
|
|
|
} while (!PPLevelBranchIndex.empty());
|
2013-01-05 07:34:14 +08:00
|
|
|
}
|
|
|
|
|
2013-04-12 22:13:36 +08:00
|
|
|
void UnwrappedLineParser::parseFile() {
|
2015-05-05 16:40:32 +08:00
|
|
|
// The top-level context in a file always has declarations, except for pre-
|
|
|
|
// processor directives and JavaScript files.
|
|
|
|
bool MustBeDeclaration =
|
|
|
|
!Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript;
|
|
|
|
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
|
|
|
|
MustBeDeclaration);
|
2017-07-03 23:05:14 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_TextProto)
|
|
|
|
parseBracedList();
|
|
|
|
else
|
|
|
|
parseLevel(/*HasOpeningBrace=*/false);
|
2013-01-05 07:34:14 +08:00
|
|
|
// Make sure to format the remaining tokens.
|
2018-06-25 19:08:24 +08:00
|
|
|
//
|
|
|
|
// LK_TextProto is special since its top-level is parsed as the body of a
|
|
|
|
// braced list, which does not necessarily have natural line separators such
|
|
|
|
// as a semicolon. Comments after the last entry that have been determined to
|
|
|
|
// not belong to that line, as in:
|
|
|
|
// key: value
|
|
|
|
// // endfile comment
|
|
|
|
// do not have a chance to be put on a line of their own until this point.
|
|
|
|
// Here we add this newline before end-of-file comments.
|
|
|
|
if (Style.Language == FormatStyle::LK_TextProto &&
|
|
|
|
!CommentsBeforeNextToken.empty())
|
|
|
|
addUnwrappedLine();
|
2013-01-23 00:31:55 +08:00
|
|
|
flushComments(true);
|
2013-01-05 07:34:14 +08:00
|
|
|
addUnwrappedLine();
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2020-03-19 20:49:15 +08:00
|
|
|
void UnwrappedLineParser::parseCSharpGenericTypeConstraint() {
|
|
|
|
do {
|
|
|
|
switch (FormatTok->Tok.getKind()) {
|
|
|
|
case tok::l_brace:
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
if (FormatTok->is(Keywords.kw_where)) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
nextToken();
|
|
|
|
parseCSharpGenericTypeConstraint();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2020-02-10 16:17:42 +08:00
|
|
|
void UnwrappedLineParser::parseCSharpAttribute() {
|
2020-03-04 01:15:56 +08:00
|
|
|
int UnpairedSquareBrackets = 1;
|
2020-02-10 16:17:42 +08:00
|
|
|
do {
|
|
|
|
switch (FormatTok->Tok.getKind()) {
|
|
|
|
case tok::r_square:
|
|
|
|
nextToken();
|
2020-03-04 01:15:56 +08:00
|
|
|
--UnpairedSquareBrackets;
|
|
|
|
if (UnpairedSquareBrackets == 0) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case tok::l_square:
|
|
|
|
++UnpairedSquareBrackets;
|
|
|
|
nextToken();
|
|
|
|
break;
|
2020-02-10 16:17:42 +08:00
|
|
|
default:
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2013-04-12 22:13:36 +08:00
|
|
|
void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
|
2013-07-25 19:31:57 +08:00
|
|
|
bool SwitchLabelEncountered = false;
|
2012-12-04 02:12:45 +08:00
|
|
|
do {
|
2015-07-04 01:25:16 +08:00
|
|
|
tok::TokenKind kind = FormatTok->Tok.getKind();
|
|
|
|
if (FormatTok->Type == TT_MacroBlockBegin) {
|
|
|
|
kind = tok::l_brace;
|
|
|
|
} else if (FormatTok->Type == TT_MacroBlockEnd) {
|
|
|
|
kind = tok::r_brace;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (kind) {
|
2012-12-04 02:12:45 +08:00
|
|
|
case tok::comment:
|
2012-12-17 19:29:41 +08:00
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
2012-12-04 02:12:45 +08:00
|
|
|
break;
|
|
|
|
case tok::l_brace:
|
2013-01-23 17:32:48 +08:00
|
|
|
// FIXME: Add parameter whether this can happen - if this happens, we must
|
|
|
|
// be in a non-declaration context.
|
2015-08-24 21:23:37 +08:00
|
|
|
if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList())
|
|
|
|
continue;
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2012-12-04 02:12:45 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
break;
|
|
|
|
case tok::r_brace:
|
2013-04-12 22:13:36 +08:00
|
|
|
if (HasOpeningBrace)
|
|
|
|
return;
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
2013-01-07 04:07:31 +08:00
|
|
|
break;
|
2018-01-24 00:30:56 +08:00
|
|
|
case tok::kw_default: {
|
|
|
|
unsigned StoredPosition = Tokens->getPosition();
|
2018-08-25 01:25:06 +08:00
|
|
|
FormatToken *Next;
|
|
|
|
do {
|
|
|
|
Next = Tokens->getNextToken();
|
|
|
|
} while (Next && Next->is(tok::comment));
|
2018-01-24 00:30:56 +08:00
|
|
|
FormatTok = Tokens->setPosition(StoredPosition);
|
|
|
|
if (Next && Next->isNot(tok::colon)) {
|
|
|
|
// default not followed by ':' is not a case label; treat it like
|
|
|
|
// an identifier.
|
|
|
|
parseStructuralElement();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Else, if it is 'default:', fall through to the case handling.
|
2018-01-24 09:47:22 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2018-01-24 00:30:56 +08:00
|
|
|
}
|
2013-07-25 19:31:57 +08:00
|
|
|
case tok::kw_case:
|
2017-09-20 17:51:03 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
Line->MustBeDeclaration) {
|
2017-08-05 01:07:15 +08:00
|
|
|
// A 'case: string' style field declaration.
|
|
|
|
parseStructuralElement();
|
|
|
|
break;
|
|
|
|
}
|
2013-09-02 16:26:29 +08:00
|
|
|
if (!SwitchLabelEncountered &&
|
|
|
|
(Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1)))
|
|
|
|
++Line->Level;
|
2013-07-25 19:31:57 +08:00
|
|
|
SwitchLabelEncountered = true;
|
|
|
|
parseStructuralElement();
|
|
|
|
break;
|
2020-02-10 16:17:42 +08:00
|
|
|
case tok::l_square:
|
|
|
|
if (Style.isCSharp()) {
|
|
|
|
nextToken();
|
|
|
|
parseCSharpAttribute();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
LLVM_FALLTHROUGH;
|
2012-12-04 02:12:45 +08:00
|
|
|
default:
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2012-12-04 02:12:45 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2015-05-18 20:52:00 +08:00
|
|
|
void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
|
2013-05-23 17:41:43 +08:00
|
|
|
// We'll parse forward through the tokens until we hit
|
|
|
|
// a closing brace or eof - note that getNextToken() will
|
|
|
|
// parse macros, so this will magically work inside macro
|
|
|
|
// definitions, too.
|
|
|
|
unsigned StoredPosition = Tokens->getPosition();
|
2013-05-28 19:55:06 +08:00
|
|
|
FormatToken *Tok = FormatTok;
|
2017-09-20 17:51:03 +08:00
|
|
|
const FormatToken *PrevTok = Tok->Previous;
|
2013-05-23 17:41:43 +08:00
|
|
|
// Keep a stack of positions of lbrace tokens. We will
|
|
|
|
// update information about whether an lbrace starts a
|
|
|
|
// braced init list or a different block during the loop.
|
2013-07-09 17:06:29 +08:00
|
|
|
SmallVector<FormatToken *, 8> LBraceStack;
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(Tok->Tok.is(tok::l_brace));
|
2013-05-23 17:41:43 +08:00
|
|
|
do {
|
2015-12-22 02:31:15 +08:00
|
|
|
// Get next non-comment token.
|
2013-07-01 17:15:46 +08:00
|
|
|
FormatToken *NextTok;
|
2013-07-02 00:43:38 +08:00
|
|
|
unsigned ReadTokens = 0;
|
2013-07-01 17:15:46 +08:00
|
|
|
do {
|
|
|
|
NextTok = Tokens->getNextToken();
|
2013-07-02 00:43:38 +08:00
|
|
|
++ReadTokens;
|
2013-07-01 17:15:46 +08:00
|
|
|
} while (NextTok->is(tok::comment));
|
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
switch (Tok->Tok.getKind()) {
|
2013-05-23 17:41:43 +08:00
|
|
|
case tok::l_brace:
|
2017-05-31 17:29:40 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
|
2017-11-25 17:33:47 +08:00
|
|
|
if (PrevTok->isOneOf(tok::colon, tok::less))
|
|
|
|
// A ':' indicates this code is in a type, or a braced list
|
|
|
|
// following a label in an object literal ({a: {b: 1}}).
|
|
|
|
// A '<' could be an object used in a comparison, but that is nonsense
|
|
|
|
// code (can never return true), so more likely it is a generic type
|
|
|
|
// argument (`X<{a: string; b: number}>`).
|
|
|
|
// The code below could be confused by semicolons between the
|
|
|
|
// individual members in a type member list, which would normally
|
|
|
|
// trigger BK_Block. In both cases, this must be parsed as an inline
|
|
|
|
// braced init.
|
2017-05-31 17:29:40 +08:00
|
|
|
Tok->BlockKind = BK_BracedInit;
|
|
|
|
else if (PrevTok->is(tok::r_paren))
|
|
|
|
// `) { }` can only occur in function or method declarations in JS.
|
|
|
|
Tok->BlockKind = BK_Block;
|
|
|
|
} else {
|
2016-01-09 23:56:28 +08:00
|
|
|
Tok->BlockKind = BK_Unknown;
|
2017-05-31 17:29:40 +08:00
|
|
|
}
|
2013-07-09 17:06:29 +08:00
|
|
|
LBraceStack.push_back(Tok);
|
2013-05-23 17:41:43 +08:00
|
|
|
break;
|
|
|
|
case tok::r_brace:
|
2016-01-09 23:56:28 +08:00
|
|
|
if (LBraceStack.empty())
|
|
|
|
break;
|
|
|
|
if (LBraceStack.back()->BlockKind == BK_Unknown) {
|
|
|
|
bool ProbablyBracedList = false;
|
|
|
|
if (Style.Language == FormatStyle::LK_Proto) {
|
|
|
|
ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
|
|
|
|
} else {
|
|
|
|
// Using OriginalColumn to distinguish between ObjC methods and
|
|
|
|
// binary operators is a bit hacky.
|
|
|
|
bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
|
|
|
|
NextTok->OriginalColumn == 0;
|
|
|
|
|
|
|
|
// If there is a comma, semicolon or right paren after the closing
|
|
|
|
// brace, we assume this is a braced initializer list. Note that
|
|
|
|
// regardless how we mark inner braces here, we will overwrite the
|
|
|
|
// BlockKind later if we parse a braced list (where all blocks
|
|
|
|
// inside are by default braced lists), or when we explicitly detect
|
|
|
|
// blocks (for example while parsing lambdas).
|
2017-05-31 17:29:40 +08:00
|
|
|
// FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
|
|
|
|
// braced list in JS.
|
2016-01-09 23:56:28 +08:00
|
|
|
ProbablyBracedList =
|
2016-03-06 02:34:26 +08:00
|
|
|
(Style.Language == FormatStyle::LK_JavaScript &&
|
2016-08-19 22:35:01 +08:00
|
|
|
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
|
|
|
|
Keywords.kw_as)) ||
|
2017-05-10 21:53:29 +08:00
|
|
|
(Style.isCpp() && NextTok->is(tok::l_paren)) ||
|
2016-01-09 23:56:28 +08:00
|
|
|
NextTok->isOneOf(tok::comma, tok::period, tok::colon,
|
|
|
|
tok::r_paren, tok::r_square, tok::l_brace,
|
2018-04-11 22:51:54 +08:00
|
|
|
tok::ellipsis) ||
|
2016-12-13 18:05:03 +08:00
|
|
|
(NextTok->is(tok::identifier) &&
|
|
|
|
!PrevTok->isOneOf(tok::semi, tok::r_brace, tok::l_brace)) ||
|
2016-01-09 23:56:28 +08:00
|
|
|
(NextTok->is(tok::semi) &&
|
|
|
|
(!ExpectClassBody || LBraceStack.size() != 1)) ||
|
|
|
|
(NextTok->isBinaryOperator() && !NextIsObjCMethod);
|
2019-12-21 01:04:49 +08:00
|
|
|
if (!Style.isCSharp() && NextTok->is(tok::l_square)) {
|
2018-04-11 22:51:54 +08:00
|
|
|
// We can have an array subscript after a braced init
|
|
|
|
// list, but C++11 attributes are expected after blocks.
|
|
|
|
NextTok = Tokens->getNextToken();
|
|
|
|
++ReadTokens;
|
|
|
|
ProbablyBracedList = NextTok->isNot(tok::l_square);
|
|
|
|
}
|
2016-01-09 23:56:28 +08:00
|
|
|
}
|
|
|
|
if (ProbablyBracedList) {
|
|
|
|
Tok->BlockKind = BK_BracedInit;
|
|
|
|
LBraceStack.back()->BlockKind = BK_BracedInit;
|
|
|
|
} else {
|
|
|
|
Tok->BlockKind = BK_Block;
|
|
|
|
LBraceStack.back()->BlockKind = BK_Block;
|
2013-05-23 17:41:43 +08:00
|
|
|
}
|
|
|
|
}
|
2016-01-09 23:56:28 +08:00
|
|
|
LBraceStack.pop_back();
|
2013-05-23 17:41:43 +08:00
|
|
|
break;
|
clang-format: better handle statement macros
Summary:
Some macros are used in the body of function, and actually contain the trailing semicolon: they should thus be automatically followed by a new line, and not get merged with the next line. This is for example the case with Qt's Q_UNUSED macro:
void foo(int a, int b) {
Q_UNUSED(a)
return b;
}
This patch deals with these cases by introducing a new option to specify list of statement macros. This re-uses the system already in place for foreach macros, to ensure there is no impact on performance.
Reviewers: krasimir, djasper, klimek
Reviewed By: krasimir
Subscribers: acoomans, mgrang, alexfh, klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D33440
llvm-svn: 343602
2018-10-03 00:37:51 +08:00
|
|
|
case tok::identifier:
|
|
|
|
if (!Tok->is(TT_StatementMacro))
|
2019-03-01 17:09:54 +08:00
|
|
|
break;
|
clang-format: better handle statement macros
Summary:
Some macros are used in the body of function, and actually contain the trailing semicolon: they should thus be automatically followed by a new line, and not get merged with the next line. This is for example the case with Qt's Q_UNUSED macro:
void foo(int a, int b) {
Q_UNUSED(a)
return b;
}
This patch deals with these cases by introducing a new option to specify list of statement macros. This re-uses the system already in place for foreach macros, to ensure there is no impact on performance.
Reviewers: krasimir, djasper, klimek
Reviewed By: krasimir
Subscribers: acoomans, mgrang, alexfh, klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D33440
llvm-svn: 343602
2018-10-03 00:37:51 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2014-03-13 18:11:17 +08:00
|
|
|
case tok::at:
|
2013-05-23 17:41:43 +08:00
|
|
|
case tok::semi:
|
|
|
|
case tok::kw_if:
|
|
|
|
case tok::kw_while:
|
|
|
|
case tok::kw_for:
|
|
|
|
case tok::kw_switch:
|
|
|
|
case tok::kw_try:
|
2015-02-04 23:26:27 +08:00
|
|
|
case tok::kw___try:
|
2016-01-09 23:56:28 +08:00
|
|
|
if (!LBraceStack.empty() && LBraceStack.back()->BlockKind == BK_Unknown)
|
2013-07-09 17:06:29 +08:00
|
|
|
LBraceStack.back()->BlockKind = BK_Block;
|
2013-05-23 17:41:43 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-01-09 23:56:28 +08:00
|
|
|
PrevTok = Tok;
|
2013-05-23 17:41:43 +08:00
|
|
|
Tok = NextTok;
|
2013-09-04 16:20:47 +08:00
|
|
|
} while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty());
|
2016-01-09 23:56:28 +08:00
|
|
|
|
2013-05-23 17:41:43 +08:00
|
|
|
// Assume other blocks for all unclosed opening braces.
|
|
|
|
for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) {
|
2013-07-09 17:06:29 +08:00
|
|
|
if (LBraceStack[i]->BlockKind == BK_Unknown)
|
|
|
|
LBraceStack[i]->BlockKind = BK_Block;
|
2013-05-23 17:41:43 +08:00
|
|
|
}
|
2013-09-04 16:20:47 +08:00
|
|
|
|
2013-05-23 17:41:43 +08:00
|
|
|
FormatTok = Tokens->setPosition(StoredPosition);
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:56:14 +08:00
|
|
|
template <class T>
|
|
|
|
static inline void hash_combine(std::size_t &seed, const T &v) {
|
|
|
|
std::hash<T> hasher;
|
|
|
|
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t UnwrappedLineParser::computePPHash() const {
|
|
|
|
size_t h = 0;
|
|
|
|
for (const auto &i : PPStack) {
|
|
|
|
hash_combine(h, size_t(i.Kind));
|
|
|
|
hash_combine(h, i.Line);
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2013-10-13 06:46:56 +08:00
|
|
|
void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
|
|
|
|
bool MunchSemi) {
|
2015-07-04 01:25:16 +08:00
|
|
|
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
|
|
|
|
"'{' or macro block token expected");
|
|
|
|
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
|
2015-12-22 02:31:15 +08:00
|
|
|
FormatTok->BlockKind = BK_Block;
|
2015-07-04 01:25:16 +08:00
|
|
|
|
2017-07-28 15:56:14 +08:00
|
|
|
size_t PPStartHash = computePPHash();
|
|
|
|
|
2013-07-25 19:31:57 +08:00
|
|
|
unsigned InitialLevel = Line->Level;
|
2017-07-24 22:51:59 +08:00
|
|
|
nextToken(/*LevelDifference=*/AddLevel ? 1 : 0);
|
2012-12-04 02:12:45 +08:00
|
|
|
|
2015-07-04 01:25:16 +08:00
|
|
|
if (MacroBlock && FormatTok->is(tok::l_paren))
|
|
|
|
parseParens();
|
|
|
|
|
2017-07-28 15:56:14 +08:00
|
|
|
size_t NbPreprocessorDirectives =
|
|
|
|
CurrentLines == &Lines ? PreprocessorDirectives.size() : 0;
|
2013-01-22 00:42:44 +08:00
|
|
|
addUnwrappedLine();
|
2017-07-28 15:56:14 +08:00
|
|
|
size_t OpeningLineIndex =
|
|
|
|
CurrentLines->empty()
|
|
|
|
? (UnwrappedLine::kInvalidIndex)
|
|
|
|
: (CurrentLines->size() - 1 - NbPreprocessorDirectives);
|
2012-12-04 02:12:45 +08:00
|
|
|
|
2013-01-23 17:32:48 +08:00
|
|
|
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
|
|
|
|
MustBeDeclaration);
|
2013-08-01 07:16:02 +08:00
|
|
|
if (AddLevel)
|
|
|
|
++Line->Level;
|
2013-06-26 08:30:14 +08:00
|
|
|
parseLevel(/*HasOpeningBrace=*/true);
|
2012-12-07 02:03:27 +08:00
|
|
|
|
2016-04-14 22:56:49 +08:00
|
|
|
if (eof())
|
|
|
|
return;
|
|
|
|
|
2015-07-04 01:25:16 +08:00
|
|
|
if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd)
|
|
|
|
: !FormatTok->is(tok::r_brace)) {
|
2013-07-25 19:31:57 +08:00
|
|
|
Line->Level = InitialLevel;
|
2015-12-22 02:31:15 +08:00
|
|
|
FormatTok->BlockKind = BK_Block;
|
2013-04-12 22:13:36 +08:00
|
|
|
return;
|
2013-01-23 00:31:55 +08:00
|
|
|
}
|
2012-12-04 23:40:36 +08:00
|
|
|
|
2017-07-28 15:56:14 +08:00
|
|
|
size_t PPEndHash = computePPHash();
|
|
|
|
|
2017-07-24 22:51:59 +08:00
|
|
|
// Munch the closing brace.
|
|
|
|
nextToken(/*LevelDifference=*/AddLevel ? -1 : 0);
|
2015-07-04 01:25:16 +08:00
|
|
|
|
|
|
|
if (MacroBlock && FormatTok->is(tok::l_paren))
|
|
|
|
parseParens();
|
|
|
|
|
2013-10-13 06:46:56 +08:00
|
|
|
if (MunchSemi && FormatTok->Tok.is(tok::semi))
|
|
|
|
nextToken();
|
2017-07-24 22:51:59 +08:00
|
|
|
Line->Level = InitialLevel;
|
2017-07-28 15:56:14 +08:00
|
|
|
|
|
|
|
if (PPStartHash == PPEndHash) {
|
|
|
|
Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
|
|
|
|
if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
|
|
|
|
// Update the opening line to add the forward reference as well
|
2018-04-23 17:34:26 +08:00
|
|
|
(*CurrentLines)[OpeningLineIndex].MatchingClosingBlockLineIndex =
|
2017-07-28 15:56:14 +08:00
|
|
|
CurrentLines->size() - 1;
|
|
|
|
}
|
2017-06-14 20:29:47 +08:00
|
|
|
}
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2015-03-30 17:56:50 +08:00
|
|
|
static bool isGoogScope(const UnwrappedLine &Line) {
|
2014-11-24 00:46:28 +08:00
|
|
|
// FIXME: Closure-library specific stuff should not be hard-coded but be
|
|
|
|
// configurable.
|
2014-05-06 21:54:10 +08:00
|
|
|
if (Line.Tokens.size() < 4)
|
|
|
|
return false;
|
|
|
|
auto I = Line.Tokens.begin();
|
|
|
|
if (I->Tok->TokenText != "goog")
|
|
|
|
return false;
|
|
|
|
++I;
|
|
|
|
if (I->Tok->isNot(tok::period))
|
|
|
|
return false;
|
|
|
|
++I;
|
|
|
|
if (I->Tok->TokenText != "scope")
|
|
|
|
return false;
|
|
|
|
++I;
|
|
|
|
return I->Tok->is(tok::l_paren);
|
|
|
|
}
|
|
|
|
|
2017-05-10 04:04:09 +08:00
|
|
|
static bool isIIFE(const UnwrappedLine &Line,
|
|
|
|
const AdditionalKeywords &Keywords) {
|
|
|
|
// Look for the start of an immediately invoked anonymous function.
|
|
|
|
// https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
|
|
|
|
// This is commonly done in JavaScript to create a new, anonymous scope.
|
|
|
|
// Example: (function() { ... })()
|
|
|
|
if (Line.Tokens.size() < 3)
|
|
|
|
return false;
|
|
|
|
auto I = Line.Tokens.begin();
|
|
|
|
if (I->Tok->isNot(tok::l_paren))
|
|
|
|
return false;
|
|
|
|
++I;
|
|
|
|
if (I->Tok->isNot(Keywords.kw_function))
|
|
|
|
return false;
|
|
|
|
++I;
|
|
|
|
return I->Tok->is(tok::l_paren);
|
|
|
|
}
|
|
|
|
|
2014-08-11 20:18:01 +08:00
|
|
|
static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
|
|
|
|
const FormatToken &InitialToken) {
|
2019-06-07 04:06:23 +08:00
|
|
|
if (InitialToken.isOneOf(tok::kw_namespace, TT_NamespaceMacro))
|
2015-09-29 22:57:55 +08:00
|
|
|
return Style.BraceWrapping.AfterNamespace;
|
|
|
|
if (InitialToken.is(tok::kw_class))
|
|
|
|
return Style.BraceWrapping.AfterClass;
|
|
|
|
if (InitialToken.is(tok::kw_union))
|
|
|
|
return Style.BraceWrapping.AfterUnion;
|
|
|
|
if (InitialToken.is(tok::kw_struct))
|
|
|
|
return Style.BraceWrapping.AfterStruct;
|
|
|
|
return false;
|
2014-08-11 20:18:01 +08:00
|
|
|
}
|
|
|
|
|
2013-09-04 21:25:30 +08:00
|
|
|
void UnwrappedLineParser::parseChildBlock() {
|
|
|
|
FormatTok->BlockKind = BK_Block;
|
|
|
|
nextToken();
|
|
|
|
{
|
2017-09-20 17:51:03 +08:00
|
|
|
bool SkipIndent = (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
(isGoogScope(*Line) || isIIFE(*Line, Keywords)));
|
2013-09-04 21:25:30 +08:00
|
|
|
ScopedLineState LineState(*this);
|
|
|
|
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
|
|
|
|
/*MustBeDeclaration=*/false);
|
2017-05-10 04:04:09 +08:00
|
|
|
Line->Level += SkipIndent ? 0 : 1;
|
2013-09-04 21:25:30 +08:00
|
|
|
parseLevel(/*HasOpeningBrace=*/true);
|
2015-03-30 17:56:50 +08:00
|
|
|
flushComments(isOnNewLine(*FormatTok));
|
2017-05-10 04:04:09 +08:00
|
|
|
Line->Level -= SkipIndent ? 0 : 1;
|
2013-09-04 21:25:30 +08:00
|
|
|
}
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
|
2012-12-04 02:12:45 +08:00
|
|
|
void UnwrappedLineParser::parsePPDirective() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::hash) && "'#' expected");
|
2015-05-06 19:56:29 +08:00
|
|
|
ScopedMacroState MacroState(*Line, Tokens, FormatTok);
|
[clang-format] BeforeHash added to IndentPPDirectives
Summary:
The option BeforeHash added to IndentPPDirectives.
Fixes Bug 36019. https://bugs.llvm.org/show_bug.cgi?id=36019
Reviewers: djasper, klimek, krasimir, sammccall, mprobst, Nicola, MyDeveloperDay
Reviewed By: klimek, MyDeveloperDay
Subscribers: kadircet, MyDeveloperDay, mnussbaum, geleji, ufna, cfe-commits
Patch by to-mix.
Differential Revision: https://reviews.llvm.org/D52150
llvm-svn: 356613
2019-03-21 04:49:43 +08:00
|
|
|
|
2013-01-03 00:30:12 +08:00
|
|
|
nextToken();
|
|
|
|
|
2014-05-09 16:15:10 +08:00
|
|
|
if (!FormatTok->Tok.getIdentifierInfo()) {
|
2013-01-31 23:58:48 +08:00
|
|
|
parsePPUnknown();
|
2013-01-03 00:30:12 +08:00
|
|
|
return;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
2013-01-03 00:30:12 +08:00
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
switch (FormatTok->Tok.getIdentifierInfo()->getPPKeywordID()) {
|
2013-01-05 07:34:14 +08:00
|
|
|
case tok::pp_define:
|
|
|
|
parsePPDefine();
|
2013-05-25 02:24:24 +08:00
|
|
|
return;
|
|
|
|
case tok::pp_if:
|
2013-10-12 05:25:45 +08:00
|
|
|
parsePPIf(/*IfDef=*/false);
|
2013-05-25 02:24:24 +08:00
|
|
|
break;
|
|
|
|
case tok::pp_ifdef:
|
|
|
|
case tok::pp_ifndef:
|
2013-10-12 05:25:45 +08:00
|
|
|
parsePPIf(/*IfDef=*/true);
|
2013-05-25 02:24:24 +08:00
|
|
|
break;
|
|
|
|
case tok::pp_else:
|
|
|
|
parsePPElse();
|
|
|
|
break;
|
|
|
|
case tok::pp_elif:
|
|
|
|
parsePPElIf();
|
|
|
|
break;
|
|
|
|
case tok::pp_endif:
|
|
|
|
parsePPEndIf();
|
2013-01-05 07:34:14 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
parsePPUnknown();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-14 17:14:11 +08:00
|
|
|
void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
|
2017-07-28 15:56:14 +08:00
|
|
|
size_t Line = CurrentLines->size();
|
|
|
|
if (CurrentLines == &PreprocessorDirectives)
|
|
|
|
Line += Lines.size();
|
|
|
|
|
|
|
|
if (Unreachable ||
|
|
|
|
(!PPStack.empty() && PPStack.back().Kind == PP_Unreachable))
|
|
|
|
PPStack.push_back({PP_Unreachable, Line});
|
2013-05-25 02:24:24 +08:00
|
|
|
else
|
2017-07-28 15:56:14 +08:00
|
|
|
PPStack.push_back({PP_Conditional, Line});
|
2013-05-25 02:24:24 +08:00
|
|
|
}
|
|
|
|
|
2014-04-14 17:14:11 +08:00
|
|
|
void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
|
2013-10-12 05:25:45 +08:00
|
|
|
++PPBranchLevel;
|
|
|
|
assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
|
|
|
|
if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
|
|
|
|
PPLevelBranchIndex.push_back(0);
|
|
|
|
PPLevelBranchCount.push_back(0);
|
|
|
|
}
|
|
|
|
PPChainBranchIndex.push(0);
|
2014-04-14 17:14:11 +08:00
|
|
|
bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0;
|
|
|
|
conditionalCompilationCondition(Unreachable || Skip);
|
2013-05-25 02:24:24 +08:00
|
|
|
}
|
|
|
|
|
2014-04-14 17:14:11 +08:00
|
|
|
void UnwrappedLineParser::conditionalCompilationAlternative() {
|
2013-05-25 02:24:24 +08:00
|
|
|
if (!PPStack.empty())
|
|
|
|
PPStack.pop_back();
|
2013-10-12 05:25:45 +08:00
|
|
|
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
|
|
|
|
if (!PPChainBranchIndex.empty())
|
|
|
|
++PPChainBranchIndex.top();
|
2014-04-14 17:14:11 +08:00
|
|
|
conditionalCompilationCondition(
|
|
|
|
PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
|
|
|
|
PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top());
|
2013-05-25 02:24:24 +08:00
|
|
|
}
|
|
|
|
|
2014-04-14 17:14:11 +08:00
|
|
|
void UnwrappedLineParser::conditionalCompilationEnd() {
|
2013-10-12 05:25:45 +08:00
|
|
|
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
|
|
|
|
if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
|
|
|
|
if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) {
|
|
|
|
PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1;
|
|
|
|
}
|
|
|
|
}
|
2014-01-29 16:49:02 +08:00
|
|
|
// Guard against #endif's without #if.
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
if (PPBranchLevel > -1)
|
2014-01-29 16:49:02 +08:00
|
|
|
--PPBranchLevel;
|
2013-10-12 05:25:45 +08:00
|
|
|
if (!PPChainBranchIndex.empty())
|
|
|
|
PPChainBranchIndex.pop();
|
2013-05-25 02:24:24 +08:00
|
|
|
if (!PPStack.empty())
|
|
|
|
PPStack.pop_back();
|
2014-04-14 17:14:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parsePPIf(bool IfDef) {
|
2017-03-01 19:10:11 +08:00
|
|
|
bool IfNDef = FormatTok->is(tok::pp_ifndef);
|
2014-04-14 17:14:11 +08:00
|
|
|
nextToken();
|
2017-03-01 18:47:52 +08:00
|
|
|
bool Unreachable = false;
|
|
|
|
if (!IfDef && (FormatTok->is(tok::kw_false) || FormatTok->TokenText == "0"))
|
|
|
|
Unreachable = true;
|
2017-03-01 19:10:11 +08:00
|
|
|
if (IfDef && !IfNDef && FormatTok->TokenText == "SWIG")
|
2017-03-01 18:47:52 +08:00
|
|
|
Unreachable = true;
|
|
|
|
conditionalCompilationStart(Unreachable);
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
FormatToken *IfCondition = FormatTok;
|
|
|
|
// If there's a #ifndef on the first line, and the only lines before it are
|
|
|
|
// comments, it could be an include guard.
|
|
|
|
bool MaybeIncludeGuard = IfNDef;
|
2018-02-05 23:59:00 +08:00
|
|
|
if (IncludeGuard == IG_Inited && MaybeIncludeGuard)
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
for (auto &Line : Lines) {
|
|
|
|
if (!Line.Tokens.front().Tok->is(tok::comment)) {
|
|
|
|
MaybeIncludeGuard = false;
|
2018-02-05 23:59:00 +08:00
|
|
|
IncludeGuard = IG_Rejected;
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
--PPBranchLevel;
|
2014-04-14 17:14:11 +08:00
|
|
|
parsePPUnknown();
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
++PPBranchLevel;
|
2018-02-05 23:59:00 +08:00
|
|
|
if (IncludeGuard == IG_Inited && MaybeIncludeGuard) {
|
|
|
|
IncludeGuard = IG_IfNdefed;
|
|
|
|
IncludeGuardToken = IfCondition;
|
|
|
|
}
|
2014-04-14 17:14:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parsePPElse() {
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
// If a potential include guard has an #else, it's not an include guard.
|
2018-02-05 23:59:00 +08:00
|
|
|
if (IncludeGuard == IG_Defined && PPBranchLevel == 0)
|
|
|
|
IncludeGuard = IG_Rejected;
|
2014-04-14 17:14:11 +08:00
|
|
|
conditionalCompilationAlternative();
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
if (PPBranchLevel > -1)
|
|
|
|
--PPBranchLevel;
|
2014-04-14 17:14:11 +08:00
|
|
|
parsePPUnknown();
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
++PPBranchLevel;
|
2014-04-14 17:14:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parsePPEndIf() {
|
|
|
|
conditionalCompilationEnd();
|
2013-05-25 02:24:24 +08:00
|
|
|
parsePPUnknown();
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
// If the #endif of a potential include guard is the last thing in the file,
|
2018-02-05 23:59:00 +08:00
|
|
|
// then we found an include guard.
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
unsigned TokenPosition = Tokens->getPosition();
|
|
|
|
FormatToken *PeekNext = AllTokens[TokenPosition];
|
2018-02-05 23:59:00 +08:00
|
|
|
if (IncludeGuard == IG_Defined && PPBranchLevel == -1 &&
|
|
|
|
PeekNext->is(tok::eof) &&
|
2017-09-04 21:33:52 +08:00
|
|
|
Style.IndentPPDirectives != FormatStyle::PPDIS_None)
|
2018-02-05 23:59:00 +08:00
|
|
|
IncludeGuard = IG_Found;
|
2013-05-25 02:24:24 +08:00
|
|
|
}
|
|
|
|
|
2013-01-05 07:34:14 +08:00
|
|
|
void UnwrappedLineParser::parsePPDefine() {
|
|
|
|
nextToken();
|
|
|
|
|
2019-04-19 04:17:08 +08:00
|
|
|
if (!FormatTok->Tok.getIdentifierInfo()) {
|
2018-02-05 23:59:00 +08:00
|
|
|
IncludeGuard = IG_Rejected;
|
|
|
|
IncludeGuardToken = nullptr;
|
2013-01-05 07:34:14 +08:00
|
|
|
parsePPUnknown();
|
|
|
|
return;
|
|
|
|
}
|
2018-02-05 23:59:00 +08:00
|
|
|
|
|
|
|
if (IncludeGuard == IG_IfNdefed &&
|
|
|
|
IncludeGuardToken->TokenText == FormatTok->TokenText) {
|
|
|
|
IncludeGuard = IG_Defined;
|
|
|
|
IncludeGuardToken = nullptr;
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
for (auto &Line : Lines) {
|
|
|
|
if (!Line.Tokens.front().Tok->isOneOf(tok::comment, tok::hash)) {
|
2018-02-05 23:59:00 +08:00
|
|
|
IncludeGuard = IG_Rejected;
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-05 23:59:00 +08:00
|
|
|
|
2013-01-05 07:34:14 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.getKind() == tok::l_paren &&
|
|
|
|
FormatTok->WhitespaceRange.getBegin() ==
|
|
|
|
FormatTok->WhitespaceRange.getEnd()) {
|
2013-01-05 07:34:14 +08:00
|
|
|
parseParens();
|
|
|
|
}
|
[clang-format] BeforeHash added to IndentPPDirectives
Summary:
The option BeforeHash added to IndentPPDirectives.
Fixes Bug 36019. https://bugs.llvm.org/show_bug.cgi?id=36019
Reviewers: djasper, klimek, krasimir, sammccall, mprobst, Nicola, MyDeveloperDay
Reviewed By: klimek, MyDeveloperDay
Subscribers: kadircet, MyDeveloperDay, mnussbaum, geleji, ufna, cfe-commits
Patch by to-mix.
Differential Revision: https://reviews.llvm.org/D52150
llvm-svn: 356613
2019-03-21 04:49:43 +08:00
|
|
|
if (Style.IndentPPDirectives != FormatStyle::PPDIS_None)
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
Line->Level += PPBranchLevel + 1;
|
2013-01-05 07:34:14 +08:00
|
|
|
addUnwrappedLine();
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
++Line->Level;
|
2013-01-07 17:34:28 +08:00
|
|
|
|
|
|
|
// Errors during a preprocessor directive can only affect the layout of the
|
|
|
|
// preprocessor directive, and thus we ignore them. An alternative approach
|
|
|
|
// would be to use the same approach we use on the file level (no
|
|
|
|
// re-indentation if there was a structural error) within the macro
|
|
|
|
// definition.
|
2013-01-05 07:34:14 +08:00
|
|
|
parseFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parsePPUnknown() {
|
2013-01-03 00:30:12 +08:00
|
|
|
do {
|
|
|
|
nextToken();
|
|
|
|
} while (!eof());
|
[clang-format] BeforeHash added to IndentPPDirectives
Summary:
The option BeforeHash added to IndentPPDirectives.
Fixes Bug 36019. https://bugs.llvm.org/show_bug.cgi?id=36019
Reviewers: djasper, klimek, krasimir, sammccall, mprobst, Nicola, MyDeveloperDay
Reviewed By: klimek, MyDeveloperDay
Subscribers: kadircet, MyDeveloperDay, mnussbaum, geleji, ufna, cfe-commits
Patch by to-mix.
Differential Revision: https://reviews.llvm.org/D52150
llvm-svn: 356613
2019-03-21 04:49:43 +08:00
|
|
|
if (Style.IndentPPDirectives != FormatStyle::PPDIS_None)
|
clang-format: Add preprocessor directive indentation
Summary:
This is an implementation for [bug 17362](https://bugs.llvm.org/attachment.cgi?bugid=17362) which adds support for indenting preprocessor statements inside if/ifdef/endif. This takes previous work from fmauch (https://github.com/fmauch/clang/tree/preprocessor_indent) and makes it into a full feature.
The context of this patch is that I'm a VMware intern, and I implemented this because VMware needs the feature. As such, some decisions were made based on what VMware wants, and I would appreciate suggestions on expanding this if necessary to use-cases other people may want.
This adds a new enum config option, `IndentPPDirectives`. Values are:
* `PPDIS_None` (in config: `None`):
```
#if FOO
#if BAR
#include <foo>
#endif
#endif
```
* `PPDIS_AfterHash` (in config: `AfterHash`):
```
#if FOO
# if BAR
# include <foo>
# endif
#endif
```
This is meant to work whether spaces or tabs are used for indentation. Preprocessor indentation is independent of indentation for non-preprocessor lines.
Preprocessor indentation also attempts to ignore include guards with the checks:
1. Include guards cover the entire file
2. Include guards don't have `#else`
3. Include guards begin with
```
#ifndef <var>
#define <var>
```
This patch allows `UnwrappedLineParser::PPBranchLevel` to be decremented to -1 (the initial value is -1) so the variable can be used for indent tracking.
Defects:
* This patch does not handle the case where there's code between the `#ifndef` and `#define` but all other conditions hold. This is because when the #define line is parsed, `UnwrappedLineParser::Lines` doesn't hold the previous code line yet, so we can't detect it. This is out of the scope of this patch.
* This patch does not handle cases where legitimate lines may be outside an include guard. Examples are `#pragma once` and `#pragma GCC diagnostic`, or anything else that does not change the meaning of the file if it's included multiple times.
* This does not detect when there is a single non-preprocessor line in front of an include-guard-like structure where other conditions hold because `ScopedLineState` hides the line.
* Preprocessor indentation throws off `TokenAnnotator::setCommentLineLevels` so the indentation of comments immediately before indented preprocessor lines is toggled on each run. Fixing this issue appears to be a major change and too much complexity for this patch.
Contributed by @euhlmann!
Reviewers: djasper, klimek, krasimir
Reviewed By: djasper, krasimir
Subscribers: krasimir, mzeren-vmw, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D35955
llvm-svn: 312125
2017-08-30 22:34:57 +08:00
|
|
|
Line->Level += PPBranchLevel + 1;
|
2013-01-03 00:30:12 +08:00
|
|
|
addUnwrappedLine();
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2013-04-10 00:15:19 +08:00
|
|
|
// Here we blacklist certain tokens that are not usually the first token in an
|
|
|
|
// unwrapped line. This is used in attempt to distinguish macro calls without
|
|
|
|
// trailing semicolons from other constructs split to several lines.
|
2015-03-10 00:47:52 +08:00
|
|
|
static bool tokenCanStartNewLine(const clang::Token &Tok) {
|
2013-04-10 00:15:19 +08:00
|
|
|
// Semicolon can be a null-statement, l_square can be a start of a macro or
|
|
|
|
// a C++11 attribute, but this doesn't seem to be common.
|
|
|
|
return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) &&
|
|
|
|
Tok.isNot(tok::l_square) &&
|
|
|
|
// Tokens that can only be used as binary operators and a part of
|
|
|
|
// overloaded operator names.
|
|
|
|
Tok.isNot(tok::period) && Tok.isNot(tok::periodstar) &&
|
|
|
|
Tok.isNot(tok::arrow) && Tok.isNot(tok::arrowstar) &&
|
|
|
|
Tok.isNot(tok::less) && Tok.isNot(tok::greater) &&
|
|
|
|
Tok.isNot(tok::slash) && Tok.isNot(tok::percent) &&
|
|
|
|
Tok.isNot(tok::lessless) && Tok.isNot(tok::greatergreater) &&
|
|
|
|
Tok.isNot(tok::equal) && Tok.isNot(tok::plusequal) &&
|
|
|
|
Tok.isNot(tok::minusequal) && Tok.isNot(tok::starequal) &&
|
|
|
|
Tok.isNot(tok::slashequal) && Tok.isNot(tok::percentequal) &&
|
|
|
|
Tok.isNot(tok::ampequal) && Tok.isNot(tok::pipeequal) &&
|
|
|
|
Tok.isNot(tok::caretequal) && Tok.isNot(tok::greatergreaterequal) &&
|
|
|
|
Tok.isNot(tok::lesslessequal) &&
|
|
|
|
// Colon is used in labels, base class lists, initializer lists,
|
|
|
|
// range-based for loops, ternary operator, but should never be the
|
|
|
|
// first token in an unwrapped line.
|
2014-05-21 21:08:17 +08:00
|
|
|
Tok.isNot(tok::colon) &&
|
|
|
|
// 'noexcept' is a trailing annotation.
|
|
|
|
Tok.isNot(tok::kw_noexcept);
|
2013-04-10 00:15:19 +08:00
|
|
|
}
|
|
|
|
|
2016-04-20 02:19:06 +08:00
|
|
|
static bool mustBeJSIdent(const AdditionalKeywords &Keywords,
|
|
|
|
const FormatToken *FormatTok) {
|
2016-03-15 03:21:36 +08:00
|
|
|
// FIXME: This returns true for C/C++ keywords like 'struct'.
|
|
|
|
return FormatTok->is(tok::identifier) &&
|
|
|
|
(FormatTok->Tok.getIdentifierInfo() == nullptr ||
|
2016-11-11 00:21:02 +08:00
|
|
|
!FormatTok->isOneOf(
|
|
|
|
Keywords.kw_in, Keywords.kw_of, Keywords.kw_as, Keywords.kw_async,
|
|
|
|
Keywords.kw_await, Keywords.kw_yield, Keywords.kw_finally,
|
|
|
|
Keywords.kw_function, Keywords.kw_import, Keywords.kw_is,
|
|
|
|
Keywords.kw_let, Keywords.kw_var, tok::kw_const,
|
|
|
|
Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements,
|
2017-09-20 17:51:03 +08:00
|
|
|
Keywords.kw_instanceof, Keywords.kw_interface, Keywords.kw_throws,
|
|
|
|
Keywords.kw_from));
|
2016-03-15 03:21:36 +08:00
|
|
|
}
|
|
|
|
|
2016-04-20 02:19:06 +08:00
|
|
|
static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords,
|
|
|
|
const FormatToken *FormatTok) {
|
2016-09-19 01:21:52 +08:00
|
|
|
return FormatTok->Tok.isLiteral() ||
|
|
|
|
FormatTok->isOneOf(tok::kw_true, tok::kw_false) ||
|
|
|
|
mustBeJSIdent(Keywords, FormatTok);
|
2016-04-20 02:19:06 +08:00
|
|
|
}
|
|
|
|
|
2016-03-15 03:21:36 +08:00
|
|
|
// isJSDeclOrStmt returns true if |FormatTok| starts a declaration or statement
|
|
|
|
// when encountered after a value (see mustBeJSIdentOrValue).
|
|
|
|
static bool isJSDeclOrStmt(const AdditionalKeywords &Keywords,
|
|
|
|
const FormatToken *FormatTok) {
|
|
|
|
return FormatTok->isOneOf(
|
2016-04-25 06:05:09 +08:00
|
|
|
tok::kw_return, Keywords.kw_yield,
|
2016-03-15 03:21:36 +08:00
|
|
|
// conditionals
|
|
|
|
tok::kw_if, tok::kw_else,
|
|
|
|
// loops
|
|
|
|
tok::kw_for, tok::kw_while, tok::kw_do, tok::kw_continue, tok::kw_break,
|
|
|
|
// switch/case
|
|
|
|
tok::kw_switch, tok::kw_case,
|
|
|
|
// exceptions
|
|
|
|
tok::kw_throw, tok::kw_try, tok::kw_catch, Keywords.kw_finally,
|
|
|
|
// declaration
|
|
|
|
tok::kw_const, tok::kw_class, Keywords.kw_var, Keywords.kw_let,
|
2016-04-25 06:05:09 +08:00
|
|
|
Keywords.kw_async, Keywords.kw_function,
|
|
|
|
// import/export
|
|
|
|
Keywords.kw_import, tok::kw_export);
|
2016-03-15 03:21:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// readTokenWithJavaScriptASI reads the next token and terminates the current
|
|
|
|
// line if JavaScript Automatic Semicolon Insertion must
|
|
|
|
// happen between the current token and the next token.
|
|
|
|
//
|
|
|
|
// This method is conservative - it cannot cover all edge cases of JavaScript,
|
|
|
|
// but only aims to correctly handle certain well known cases. It *must not*
|
|
|
|
// return true in speculative cases.
|
|
|
|
void UnwrappedLineParser::readTokenWithJavaScriptASI() {
|
|
|
|
FormatToken *Previous = FormatTok;
|
|
|
|
readToken();
|
|
|
|
FormatToken *Next = FormatTok;
|
|
|
|
|
|
|
|
bool IsOnSameLine =
|
|
|
|
CommentsBeforeNextToken.empty()
|
|
|
|
? Next->NewlinesBefore == 0
|
|
|
|
: CommentsBeforeNextToken.front()->NewlinesBefore == 0;
|
|
|
|
if (IsOnSameLine)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
|
2016-10-21 13:11:38 +08:00
|
|
|
bool PreviousStartsTemplateExpr =
|
|
|
|
Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
|
2017-11-25 17:19:42 +08:00
|
|
|
if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
|
|
|
|
// If the line contains an '@' sign, the previous token might be an
|
|
|
|
// annotation, which can precede another identifier/value.
|
|
|
|
bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(),
|
|
|
|
[](UnwrappedLineNode &LineNode) {
|
|
|
|
return LineNode.Tok->is(tok::at);
|
|
|
|
}) != Line->Tokens.end();
|
|
|
|
if (HasAt)
|
2016-04-11 15:35:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2016-03-15 03:21:36 +08:00
|
|
|
if (Next->is(tok::exclaim) && PreviousMustBeValue)
|
2017-01-09 16:56:36 +08:00
|
|
|
return addUnwrappedLine();
|
2016-03-15 03:21:36 +08:00
|
|
|
bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next);
|
2016-10-21 13:11:38 +08:00
|
|
|
bool NextEndsTemplateExpr =
|
|
|
|
Next->is(TT_TemplateString) && Next->TokenText.startswith("}");
|
|
|
|
if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr &&
|
|
|
|
(PreviousMustBeValue ||
|
|
|
|
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
|
|
|
|
tok::minusminus)))
|
2017-01-09 16:56:36 +08:00
|
|
|
return addUnwrappedLine();
|
2017-08-09 23:19:16 +08:00
|
|
|
if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
|
|
|
|
isJSDeclOrStmt(Keywords, Next))
|
2017-01-09 16:56:36 +08:00
|
|
|
return addUnwrappedLine();
|
2016-03-15 03:21:36 +08:00
|
|
|
}
|
|
|
|
|
2013-01-07 22:56:16 +08:00
|
|
|
void UnwrappedLineParser::parseStructuralElement() {
|
2015-12-25 16:53:31 +08:00
|
|
|
assert(!FormatTok->is(tok::l_brace));
|
|
|
|
if (Style.Language == FormatStyle::LK_TableGen &&
|
|
|
|
FormatTok->is(tok::pp_include)) {
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::string_literal))
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
switch (FormatTok->Tok.getKind()) {
|
2014-08-27 07:15:12 +08:00
|
|
|
case tok::kw_asm:
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
2015-05-10 16:42:04 +08:00
|
|
|
FormatTok->Type = TT_InlineASMBrace;
|
2015-01-12 18:14:56 +08:00
|
|
|
nextToken();
|
2014-08-28 01:16:46 +08:00
|
|
|
while (FormatTok && FormatTok->isNot(tok::eof)) {
|
2014-08-27 07:15:12 +08:00
|
|
|
if (FormatTok->is(tok::r_brace)) {
|
2015-05-10 16:42:04 +08:00
|
|
|
FormatTok->Type = TT_InlineASMBrace;
|
2014-08-27 07:15:12 +08:00
|
|
|
nextToken();
|
2015-05-11 19:59:46 +08:00
|
|
|
addUnwrappedLine();
|
2014-08-27 07:15:12 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-01-12 18:14:56 +08:00
|
|
|
FormatTok->Finalized = true;
|
2014-08-27 07:15:12 +08:00
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-12-07 02:03:27 +08:00
|
|
|
case tok::kw_namespace:
|
|
|
|
parseNamespace();
|
|
|
|
return;
|
2012-12-04 22:46:19 +08:00
|
|
|
case tok::kw_public:
|
|
|
|
case tok::kw_protected:
|
|
|
|
case tok::kw_private:
|
2015-02-19 01:14:05 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Java ||
|
[clang-format] Add basic support for formatting C# files
Summary:
This revision adds basic support for formatting C# files with clang-format, I know the barrier to entry is high here so I'm sending this revision in to test the water as to whether this might be something we'd consider landing.
Tracking in Bugzilla as:
https://bugs.llvm.org/show_bug.cgi?id=40850
Justification:
C# code just looks ugly in comparison to the C++ code in our source tree which is clang-formatted.
I've struggled with Visual Studio reformatting to get a clean and consistent style, I want to format our C# code on saving like I do now for C++ and i want it to have the same style as defined in our .clang-format file, so it consistent as it can be with C++. (Braces/Breaking/Spaces/Indent etc..)
Using clang format without this patch leaves the code in a bad state, sometimes when the BreakStringLiterals is set, it fails to compile.
Mostly the C# is similar to Java, except instead of JavaAnnotations I try to reuse the TT_AttributeSquare.
Almost the most valuable portion is to have a new Language in order to partition the configuration for C# within a common .clang-format file, with the auto detection on the .cs extension. But there are other C# specific styles that could be added later if this is accepted. in particular how `{ set;get }` is formatted.
Reviewers: djasper, klimek, krasimir, benhamilton, JonasToth
Reviewed By: klimek
Subscribers: llvm-commits, mgorny, jdoerfert, cfe-commits
Tags: #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D58404
llvm-svn: 356662
2019-03-21 21:09:22 +08:00
|
|
|
Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp())
|
2014-09-15 19:21:46 +08:00
|
|
|
nextToken();
|
|
|
|
else
|
|
|
|
parseAccessSpecifier();
|
2012-12-04 02:12:45 +08:00
|
|
|
return;
|
2012-12-04 22:46:19 +08:00
|
|
|
case tok::kw_if:
|
2020-01-16 18:49:52 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// field/method declaration.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
parseIfThenElse();
|
|
|
|
return;
|
2012-12-05 23:06:06 +08:00
|
|
|
case tok::kw_for:
|
|
|
|
case tok::kw_while:
|
2020-01-16 18:49:52 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// field/method declaration.
|
|
|
|
break;
|
2012-12-05 23:06:06 +08:00
|
|
|
parseForOrWhileLoop();
|
|
|
|
return;
|
2012-12-04 22:46:19 +08:00
|
|
|
case tok::kw_do:
|
2020-01-16 18:49:52 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// field/method declaration.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
parseDoWhile();
|
|
|
|
return;
|
|
|
|
case tok::kw_switch:
|
2017-08-05 01:07:15 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// 'switch: string' field declaration.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
parseSwitch();
|
|
|
|
return;
|
|
|
|
case tok::kw_default:
|
2017-08-05 01:07:15 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// 'default: string' field declaration.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
nextToken();
|
2018-01-24 00:30:56 +08:00
|
|
|
if (FormatTok->is(tok::colon)) {
|
|
|
|
parseLabel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// e.g. "default void f() {}" in a Java interface.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
case tok::kw_case:
|
2017-08-05 01:07:15 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// 'case: string' field declaration.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
parseCaseLabel();
|
2012-12-04 02:12:45 +08:00
|
|
|
return;
|
2014-05-08 19:58:24 +08:00
|
|
|
case tok::kw_try:
|
2015-02-04 23:26:27 +08:00
|
|
|
case tok::kw___try:
|
2020-01-16 18:49:52 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
|
|
|
|
// field/method declaration.
|
|
|
|
break;
|
2014-05-08 19:58:24 +08:00
|
|
|
parseTryCatch();
|
|
|
|
return;
|
2013-01-21 22:32:05 +08:00
|
|
|
case tok::kw_extern:
|
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::string_literal)) {
|
2013-01-21 22:32:05 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2017-09-15 19:23:50 +08:00
|
|
|
if (Style.BraceWrapping.AfterExternBlock) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
parseBlock(/*MustBeDeclaration=*/true);
|
|
|
|
} else {
|
|
|
|
parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false);
|
|
|
|
}
|
2013-01-21 22:32:05 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-04-01 20:55:11 +08:00
|
|
|
break;
|
2015-02-20 00:14:18 +08:00
|
|
|
case tok::kw_export:
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
parseJavaScriptEs6ImportExport();
|
|
|
|
return;
|
|
|
|
}
|
2018-09-05 15:44:02 +08:00
|
|
|
if (!Style.isCpp())
|
|
|
|
break;
|
|
|
|
// Handle C++ "(inline|export) namespace".
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case tok::kw_inline:
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->Tok.is(tok::kw_namespace)) {
|
|
|
|
parseNamespace();
|
|
|
|
return;
|
|
|
|
}
|
2015-02-20 00:14:18 +08:00
|
|
|
break;
|
2014-04-01 20:55:11 +08:00
|
|
|
case tok::identifier:
|
2015-05-04 17:22:29 +08:00
|
|
|
if (FormatTok->is(TT_ForEachMacro)) {
|
2014-04-01 20:55:11 +08:00
|
|
|
parseForOrWhileLoop();
|
|
|
|
return;
|
|
|
|
}
|
2015-07-04 01:25:16 +08:00
|
|
|
if (FormatTok->is(TT_MacroBlockBegin)) {
|
|
|
|
parseBlock(/*MustBeDeclaration=*/false, /*AddLevel=*/true,
|
|
|
|
/*MunchSemi=*/false);
|
|
|
|
return;
|
|
|
|
}
|
2016-06-21 02:20:38 +08:00
|
|
|
if (FormatTok->is(Keywords.kw_import)) {
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
parseJavaScriptEs6ImportExport();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Style.Language == FormatStyle::LK_Proto) {
|
|
|
|
nextToken();
|
2016-06-21 04:39:53 +08:00
|
|
|
if (FormatTok->is(tok::kw_public))
|
|
|
|
nextToken();
|
2016-06-21 02:20:38 +08:00
|
|
|
if (!FormatTok->is(tok::string_literal))
|
|
|
|
return;
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
2015-02-20 00:07:32 +08:00
|
|
|
}
|
2017-03-31 21:30:24 +08:00
|
|
|
if (Style.isCpp() &&
|
2017-03-31 20:04:37 +08:00
|
|
|
FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
|
2015-12-01 20:05:04 +08:00
|
|
|
Keywords.kw_slots, Keywords.kw_qslots)) {
|
2015-04-24 15:50:34 +08:00
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::colon)) {
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
2016-07-27 18:13:24 +08:00
|
|
|
return;
|
2015-04-24 15:50:34 +08:00
|
|
|
}
|
2015-04-07 23:04:40 +08:00
|
|
|
}
|
clang-format: better handle statement macros
Summary:
Some macros are used in the body of function, and actually contain the trailing semicolon: they should thus be automatically followed by a new line, and not get merged with the next line. This is for example the case with Qt's Q_UNUSED macro:
void foo(int a, int b) {
Q_UNUSED(a)
return b;
}
This patch deals with these cases by introducing a new option to specify list of statement macros. This re-uses the system already in place for foreach macros, to ensure there is no impact on performance.
Reviewers: krasimir, djasper, klimek
Reviewed By: krasimir
Subscribers: acoomans, mgrang, alexfh, klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D33440
llvm-svn: 343602
2018-10-03 00:37:51 +08:00
|
|
|
if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
|
|
|
|
parseStatementMacro();
|
|
|
|
return;
|
|
|
|
}
|
2019-06-07 04:06:23 +08:00
|
|
|
if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
|
|
|
|
parseNamespace();
|
|
|
|
return;
|
|
|
|
}
|
2013-01-21 22:32:05 +08:00
|
|
|
// In all other cases, parse the declaration.
|
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
default:
|
|
|
|
break;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
do {
|
2017-09-20 17:29:37 +08:00
|
|
|
const FormatToken *Previous = FormatTok->Previous;
|
2013-05-28 19:55:06 +08:00
|
|
|
switch (FormatTok->Tok.getKind()) {
|
2013-02-11 04:35:35 +08:00
|
|
|
case tok::at:
|
|
|
|
nextToken();
|
2017-07-03 23:05:14 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
|
|
|
nextToken();
|
2013-02-11 04:35:35 +08:00
|
|
|
parseBracedList();
|
2018-01-24 01:10:25 +08:00
|
|
|
break;
|
2018-10-20 00:19:52 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Java &&
|
|
|
|
FormatTok->is(Keywords.kw_interface)) {
|
|
|
|
nextToken();
|
|
|
|
break;
|
2018-01-24 01:10:25 +08:00
|
|
|
}
|
|
|
|
switch (FormatTok->Tok.getObjCKeywordID()) {
|
|
|
|
case tok::objc_public:
|
|
|
|
case tok::objc_protected:
|
|
|
|
case tok::objc_package:
|
|
|
|
case tok::objc_private:
|
|
|
|
return parseAccessSpecifier();
|
|
|
|
case tok::objc_interface:
|
|
|
|
case tok::objc_implementation:
|
|
|
|
return parseObjCInterfaceOrImplementation();
|
|
|
|
case tok::objc_protocol:
|
|
|
|
if (parseObjCProtocol())
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
case tok::objc_end:
|
|
|
|
return; // Handled by the caller.
|
|
|
|
case tok::objc_optional:
|
|
|
|
case tok::objc_required:
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
case tok::objc_autoreleasepool:
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
[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-04 02:42:31 +08:00
|
|
|
if (Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always)
|
2018-01-24 01:10:25 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
|
|
|
}
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
2018-02-27 21:48:21 +08:00
|
|
|
case tok::objc_synchronized:
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->Tok.is(tok::l_paren))
|
2019-03-01 17:09:54 +08:00
|
|
|
// Skip synchronization object
|
|
|
|
parseParens();
|
2018-02-27 21:48:21 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
[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-04 02:42:31 +08:00
|
|
|
if (Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always)
|
2018-02-27 21:48:21 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
|
|
|
}
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
2018-01-24 01:10:25 +08:00
|
|
|
case tok::objc_try:
|
|
|
|
// This branch isn't strictly necessary (the kw_try case below would
|
|
|
|
// do this too after the tok::at is parsed above). But be explicit.
|
|
|
|
parseTryCatch();
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
2017-07-03 23:05:14 +08:00
|
|
|
}
|
2013-02-11 04:35:35 +08:00
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
case tok::kw_enum:
|
2016-05-09 02:12:22 +08:00
|
|
|
// Ignore if this is part of "template <enum ...".
|
|
|
|
if (Previous && Previous->is(tok::less)) {
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-17 17:44:02 +08:00
|
|
|
// parseEnum falls through and does not yet add an unwrapped line as an
|
|
|
|
// enum definition can start a structural element.
|
2015-12-29 16:54:23 +08:00
|
|
|
if (!parseEnum())
|
|
|
|
break;
|
2015-07-16 22:25:43 +08:00
|
|
|
// This only applies for C++.
|
2017-03-31 21:30:24 +08:00
|
|
|
if (!Style.isCpp()) {
|
2015-06-17 17:44:02 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
2013-01-22 03:17:52 +08:00
|
|
|
break;
|
2014-01-30 22:38:37 +08:00
|
|
|
case tok::kw_typedef:
|
|
|
|
nextToken();
|
2014-12-05 18:42:21 +08:00
|
|
|
if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
|
2019-07-23 02:20:01 +08:00
|
|
|
Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS,
|
2019-07-29 21:26:48 +08:00
|
|
|
Keywords.kw_CF_CLOSED_ENUM,
|
|
|
|
Keywords.kw_NS_CLOSED_ENUM))
|
2014-01-30 22:38:37 +08:00
|
|
|
parseEnum();
|
|
|
|
break;
|
2013-01-16 19:43:46 +08:00
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_union:
|
2013-01-08 02:10:23 +08:00
|
|
|
case tok::kw_class:
|
2015-06-12 12:52:02 +08:00
|
|
|
// parseRecord falls through and does not yet add an unwrapped line as a
|
|
|
|
// record declaration or definition can start a structural element.
|
2013-01-15 21:38:33 +08:00
|
|
|
parseRecord();
|
[clang-format] Add basic support for formatting C# files
Summary:
This revision adds basic support for formatting C# files with clang-format, I know the barrier to entry is high here so I'm sending this revision in to test the water as to whether this might be something we'd consider landing.
Tracking in Bugzilla as:
https://bugs.llvm.org/show_bug.cgi?id=40850
Justification:
C# code just looks ugly in comparison to the C++ code in our source tree which is clang-formatted.
I've struggled with Visual Studio reformatting to get a clean and consistent style, I want to format our C# code on saving like I do now for C++ and i want it to have the same style as defined in our .clang-format file, so it consistent as it can be with C++. (Braces/Breaking/Spaces/Indent etc..)
Using clang format without this patch leaves the code in a bad state, sometimes when the BreakStringLiterals is set, it fails to compile.
Mostly the C# is similar to Java, except instead of JavaAnnotations I try to reuse the TT_AttributeSquare.
Almost the most valuable portion is to have a new Language in order to partition the configuration for C# within a common .clang-format file, with the auto detection on the .cs extension. But there are other C# specific styles that could be added later if this is accepted. in particular how `{ set;get }` is formatted.
Reviewers: djasper, klimek, krasimir, benhamilton, JonasToth
Reviewed By: klimek
Subscribers: llvm-commits, mgorny, jdoerfert, cfe-commits
Tags: #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D58404
llvm-svn: 356662
2019-03-21 21:09:22 +08:00
|
|
|
// This does not apply for Java, JavaScript and C#.
|
2015-06-12 12:52:02 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Java ||
|
[clang-format] Add basic support for formatting C# files
Summary:
This revision adds basic support for formatting C# files with clang-format, I know the barrier to entry is high here so I'm sending this revision in to test the water as to whether this might be something we'd consider landing.
Tracking in Bugzilla as:
https://bugs.llvm.org/show_bug.cgi?id=40850
Justification:
C# code just looks ugly in comparison to the C++ code in our source tree which is clang-formatted.
I've struggled with Visual Studio reformatting to get a clean and consistent style, I want to format our C# code on saving like I do now for C++ and i want it to have the same style as defined in our .clang-format file, so it consistent as it can be with C++. (Braces/Breaking/Spaces/Indent etc..)
Using clang format without this patch leaves the code in a bad state, sometimes when the BreakStringLiterals is set, it fails to compile.
Mostly the C# is similar to Java, except instead of JavaAnnotations I try to reuse the TT_AttributeSquare.
Almost the most valuable portion is to have a new Language in order to partition the configuration for C# within a common .clang-format file, with the auto detection on the .cs extension. But there are other C# specific styles that could be added later if this is accepted. in particular how `{ set;get }` is formatted.
Reviewers: djasper, klimek, krasimir, benhamilton, JonasToth
Reviewed By: klimek
Subscribers: llvm-commits, mgorny, jdoerfert, cfe-commits
Tags: #clang, #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D58404
llvm-svn: 356662
2019-03-21 21:09:22 +08:00
|
|
|
Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp()) {
|
2016-01-08 15:06:07 +08:00
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
nextToken();
|
2015-06-12 12:52:02 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
2013-01-15 21:38:33 +08:00
|
|
|
break;
|
2014-11-26 16:17:08 +08:00
|
|
|
case tok::period:
|
|
|
|
nextToken();
|
|
|
|
// In Java, classes have an implicit static member "class".
|
|
|
|
if (Style.Language == FormatStyle::LK_Java && FormatTok &&
|
|
|
|
FormatTok->is(tok::kw_class))
|
|
|
|
nextToken();
|
2015-09-28 22:29:45 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript && FormatTok &&
|
|
|
|
FormatTok->Tok.getIdentifierInfo())
|
|
|
|
// JavaScript only has pseudo keywords, all keywords are allowed to
|
|
|
|
// appear in "IdentifierName" positions. See http://es5.github.io/#x7.6
|
|
|
|
nextToken();
|
2014-11-26 16:17:08 +08:00
|
|
|
break;
|
2012-12-04 02:12:45 +08:00
|
|
|
case tok::semi:
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
2013-01-16 19:43:46 +08:00
|
|
|
case tok::r_brace:
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
2012-12-04 02:12:45 +08:00
|
|
|
case tok::l_paren:
|
|
|
|
parseParens();
|
|
|
|
break;
|
2015-10-07 11:43:10 +08:00
|
|
|
case tok::kw_operator:
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->isBinaryOperator())
|
|
|
|
nextToken();
|
|
|
|
break;
|
2013-09-04 21:25:30 +08:00
|
|
|
case tok::caret:
|
|
|
|
nextToken();
|
2014-03-28 15:48:59 +08:00
|
|
|
if (FormatTok->Tok.isAnyIdentifier() ||
|
|
|
|
FormatTok->isSimpleTypeSpecifier())
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::l_paren))
|
|
|
|
parseParens();
|
|
|
|
if (FormatTok->is(tok::l_brace))
|
2013-09-04 21:25:30 +08:00
|
|
|
parseChildBlock();
|
|
|
|
break;
|
2012-12-04 02:12:45 +08:00
|
|
|
case tok::l_brace:
|
2020-04-23 18:38:52 +08:00
|
|
|
if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) {
|
2013-05-23 17:41:43 +08:00
|
|
|
// A block outside of parentheses must be the last part of a
|
|
|
|
// structural element.
|
|
|
|
// FIXME: Figure out cases where this is not true, and add projections
|
|
|
|
// for them (the one we know is missing are lambdas).
|
2015-09-29 22:57:55 +08:00
|
|
|
if (Style.BraceWrapping.AfterFunction)
|
2013-05-23 17:41:43 +08:00
|
|
|
addUnwrappedLine();
|
2013-11-21 00:33:05 +08:00
|
|
|
FormatTok->Type = TT_FunctionLBrace;
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2013-05-13 20:51:40 +08:00
|
|
|
addUnwrappedLine();
|
2013-05-23 17:41:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Otherwise this was a braced init list, and the structural
|
|
|
|
// element continues.
|
|
|
|
break;
|
2014-05-08 19:58:24 +08:00
|
|
|
case tok::kw_try:
|
2020-01-16 18:49:52 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
Line->MustBeDeclaration) {
|
|
|
|
// field/method declaration.
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
2014-05-08 19:58:24 +08:00
|
|
|
// We arrive here when parsing function-try blocks.
|
2018-09-28 17:17:00 +08:00
|
|
|
if (Style.BraceWrapping.AfterFunction)
|
|
|
|
addUnwrappedLine();
|
2014-05-08 19:58:24 +08:00
|
|
|
parseTryCatch();
|
|
|
|
return;
|
2013-05-29 21:16:10 +08:00
|
|
|
case tok::identifier: {
|
2020-03-19 20:49:15 +08:00
|
|
|
if (Style.isCSharp() && FormatTok->is(Keywords.kw_where) &&
|
|
|
|
Line->MustBeDeclaration) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
parseCSharpGenericTypeConstraint();
|
|
|
|
break;
|
|
|
|
}
|
2015-07-04 01:25:16 +08:00
|
|
|
if (FormatTok->is(TT_MacroBlockEnd)) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-27 21:07:24 +08:00
|
|
|
// Function declarations (as opposed to function expressions) are parsed
|
|
|
|
// on their own unwrapped line by continuing this loop. Function
|
|
|
|
// expressions (functions that are not on their own line) must not create
|
|
|
|
// a new unwrapped line, so they are special cased below.
|
|
|
|
size_t TokenCount = Line->Tokens.size();
|
2015-05-05 16:40:32 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
2017-04-27 21:07:24 +08:00
|
|
|
FormatTok->is(Keywords.kw_function) &&
|
|
|
|
(TokenCount > 1 || (TokenCount == 1 && !Line->Tokens.front().Tok->is(
|
|
|
|
Keywords.kw_async)))) {
|
2014-05-20 19:14:57 +08:00
|
|
|
tryToParseJSFunction();
|
|
|
|
break;
|
|
|
|
}
|
2015-05-05 16:40:32 +08:00
|
|
|
if ((Style.Language == FormatStyle::LK_JavaScript ||
|
|
|
|
Style.Language == FormatStyle::LK_Java) &&
|
|
|
|
FormatTok->is(Keywords.kw_interface)) {
|
2016-04-20 02:18:59 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
// In JavaScript/TypeScript, "interface" can be used as a standalone
|
|
|
|
// identifier, e.g. in `var interface = 1;`. If "interface" is
|
|
|
|
// followed by another identifier, it is very like to be an actual
|
|
|
|
// interface declaration.
|
|
|
|
unsigned StoredPosition = Tokens->getPosition();
|
|
|
|
FormatToken *Next = Tokens->getNextToken();
|
|
|
|
FormatTok = Tokens->setPosition(StoredPosition);
|
2016-04-20 02:19:06 +08:00
|
|
|
if (Next && !mustBeJSIdent(Keywords, Next)) {
|
2016-04-20 02:18:59 +08:00
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-05-05 16:40:32 +08:00
|
|
|
parseRecord();
|
2015-06-12 12:56:34 +08:00
|
|
|
addUnwrappedLine();
|
2015-07-06 22:26:04 +08:00
|
|
|
return;
|
2015-05-05 16:40:32 +08:00
|
|
|
}
|
|
|
|
|
clang-format: better handle statement macros
Summary:
Some macros are used in the body of function, and actually contain the trailing semicolon: they should thus be automatically followed by a new line, and not get merged with the next line. This is for example the case with Qt's Q_UNUSED macro:
void foo(int a, int b) {
Q_UNUSED(a)
return b;
}
This patch deals with these cases by introducing a new option to specify list of statement macros. This re-uses the system already in place for foreach macros, to ensure there is no impact on performance.
Reviewers: krasimir, djasper, klimek
Reviewed By: krasimir
Subscribers: acoomans, mgrang, alexfh, klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D33440
llvm-svn: 343602
2018-10-03 00:37:51 +08:00
|
|
|
if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
|
|
|
|
parseStatementMacro();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-15 03:21:36 +08:00
|
|
|
// See if the following token should start a new unwrapped line.
|
2015-05-05 16:40:32 +08:00
|
|
|
StringRef Text = FormatTok->TokenText;
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2019-05-01 23:03:41 +08:00
|
|
|
|
|
|
|
// JS doesn't have macros, and within classes colons indicate fields, not
|
|
|
|
// labels.
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript)
|
|
|
|
break;
|
|
|
|
|
|
|
|
TokenCount = Line->Tokens.size();
|
|
|
|
if (TokenCount == 1 ||
|
|
|
|
(TokenCount == 2 && Line->Tokens.front().Tok->is(tok::comment))) {
|
2015-04-07 22:36:33 +08:00
|
|
|
if (FormatTok->Tok.is(tok::colon) && !Line->MustBeDeclaration) {
|
2016-04-06 23:02:46 +08:00
|
|
|
Line->Tokens.begin()->Tok->MustBreakBefore = true;
|
2019-09-12 18:07:14 +08:00
|
|
|
parseLabel(!Style.IndentGotoLabels);
|
2013-04-09 06:16:06 +08:00
|
|
|
return;
|
|
|
|
}
|
2014-11-05 18:48:04 +08:00
|
|
|
// Recognize function-like macro usages without trailing semicolon as
|
2015-02-19 01:14:05 +08:00
|
|
|
// well as free-standing macros like Q_OBJECT.
|
2014-11-05 18:48:04 +08:00
|
|
|
bool FunctionLike = FormatTok->is(tok::l_paren);
|
|
|
|
if (FunctionLike)
|
2013-04-09 06:16:06 +08:00
|
|
|
parseParens();
|
2015-05-13 19:35:53 +08:00
|
|
|
|
|
|
|
bool FollowedByNewline =
|
|
|
|
CommentsBeforeNextToken.empty()
|
|
|
|
? FormatTok->NewlinesBefore > 0
|
|
|
|
: CommentsBeforeNextToken.front()->NewlinesBefore > 0;
|
|
|
|
|
2015-06-17 21:08:06 +08:00
|
|
|
if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) &&
|
2014-11-05 18:48:04 +08:00
|
|
|
tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
|
2013-05-29 21:16:10 +08:00
|
|
|
addUnwrappedLine();
|
2013-05-29 22:09:17 +08:00
|
|
|
return;
|
2013-04-09 06:16:06 +08:00
|
|
|
}
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
break;
|
2013-05-29 21:16:10 +08:00
|
|
|
}
|
2012-12-17 19:29:41 +08:00
|
|
|
case tok::equal:
|
2015-05-21 20:23:34 +08:00
|
|
|
// Fat arrows (=>) have tok::TokenKind tok::equal but TokenType
|
|
|
|
// TT_JsFatArrow. The always start an expression or a child block if
|
|
|
|
// followed by a curly.
|
|
|
|
if (FormatTok->is(TT_JsFatArrow)) {
|
|
|
|
nextToken();
|
2015-05-31 16:51:54 +08:00
|
|
|
if (FormatTok->is(tok::l_brace))
|
2015-05-21 20:23:34 +08:00
|
|
|
parseChildBlock();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-12-17 19:29:41 +08:00
|
|
|
nextToken();
|
2017-07-03 23:05:14 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2020-03-23 22:23:52 +08:00
|
|
|
// Block kind should probably be set to BK_BracedInit for any language.
|
|
|
|
// C# needs this change to ensure that array initialisers and object
|
|
|
|
// initialisers are indented the same way.
|
|
|
|
if (Style.isCSharp())
|
|
|
|
FormatTok->BlockKind = BK_BracedInit;
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2013-01-10 19:52:21 +08:00
|
|
|
parseBracedList();
|
2017-07-03 23:05:14 +08:00
|
|
|
} else if (Style.Language == FormatStyle::LK_Proto &&
|
2017-09-20 17:51:03 +08:00
|
|
|
FormatTok->Tok.is(tok::less)) {
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2020-05-01 05:34:49 +08:00
|
|
|
parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum*/false,
|
2017-06-27 21:58:41 +08:00
|
|
|
/*ClosingBraceKind=*/tok::greater);
|
2017-07-03 23:05:14 +08:00
|
|
|
}
|
2013-01-10 19:52:21 +08:00
|
|
|
break;
|
2013-09-03 23:10:01 +08:00
|
|
|
case tok::l_square:
|
2013-12-23 15:29:06 +08:00
|
|
|
parseSquare();
|
2013-09-03 23:10:01 +08:00
|
|
|
break;
|
2015-03-12 22:44:29 +08:00
|
|
|
case tok::kw_new:
|
|
|
|
parseNew();
|
|
|
|
break;
|
2013-01-10 19:52:21 +08:00
|
|
|
default:
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2020-04-23 18:38:52 +08:00
|
|
|
bool UnwrappedLineParser::tryToParsePropertyAccessor() {
|
|
|
|
assert(FormatTok->is(tok::l_brace));
|
|
|
|
if (!Style.isCSharp())
|
|
|
|
return false;
|
|
|
|
// See if it's a property accessor.
|
|
|
|
if (FormatTok->Previous->isNot(tok::identifier))
|
|
|
|
return false;
|
|
|
|
|
2020-04-28 21:11:09 +08:00
|
|
|
// See if we are inside a property accessor.
|
2020-04-23 18:38:52 +08:00
|
|
|
//
|
|
|
|
// Record the current tokenPosition so that we can advance and
|
|
|
|
// reset the current token. `Next` is not set yet so we need
|
|
|
|
// another way to advance along the token stream.
|
|
|
|
unsigned int StoredPosition = Tokens->getPosition();
|
|
|
|
FormatToken *Tok = Tokens->getNextToken();
|
|
|
|
|
2020-04-28 21:11:09 +08:00
|
|
|
// A trivial property accessor is of the form:
|
|
|
|
// { [ACCESS_SPECIFIER] [get]; [ACCESS_SPECIFIER] [set] }
|
|
|
|
// Track these as they do not require line breaks to be introduced.
|
2020-04-23 18:38:52 +08:00
|
|
|
bool HasGetOrSet = false;
|
2020-04-28 21:11:09 +08:00
|
|
|
bool IsTrivialPropertyAccessor = true;
|
2020-04-23 18:38:52 +08:00
|
|
|
while (!eof()) {
|
|
|
|
if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
|
|
|
|
tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
|
|
|
|
Keywords.kw_set)) {
|
|
|
|
if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set))
|
|
|
|
HasGetOrSet = true;
|
|
|
|
Tok = Tokens->getNextToken();
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-28 21:11:09 +08:00
|
|
|
if (Tok->isNot(tok::r_brace))
|
|
|
|
IsTrivialPropertyAccessor = false;
|
|
|
|
break;
|
2020-04-23 18:38:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!HasGetOrSet) {
|
|
|
|
Tokens->setPosition(StoredPosition);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-28 21:11:09 +08:00
|
|
|
// Try to parse the property accessor:
|
|
|
|
// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
|
2020-04-23 18:38:52 +08:00
|
|
|
Tokens->setPosition(StoredPosition);
|
2020-04-28 21:11:09 +08:00
|
|
|
nextToken();
|
|
|
|
do {
|
|
|
|
switch (FormatTok->Tok.getKind()) {
|
|
|
|
case tok::r_brace:
|
2020-04-23 18:38:52 +08:00
|
|
|
nextToken();
|
2020-04-28 21:11:09 +08:00
|
|
|
if (FormatTok->is(tok::equal)) {
|
|
|
|
while (!eof() && FormatTok->isNot(tok::semi))
|
|
|
|
nextToken();
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
addUnwrappedLine();
|
|
|
|
return true;
|
|
|
|
case tok::l_brace:
|
|
|
|
++Line->Level;
|
|
|
|
parseBlock(/*MustBeDeclaration=*/true);
|
|
|
|
addUnwrappedLine();
|
|
|
|
--Line->Level;
|
|
|
|
break;
|
|
|
|
case tok::equal:
|
|
|
|
if (FormatTok->is(TT_JsFatArrow)) {
|
|
|
|
++Line->Level;
|
|
|
|
do {
|
|
|
|
nextToken();
|
|
|
|
} while (!eof() && FormatTok->isNot(tok::semi));
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
--Line->Level;
|
2020-04-23 18:38:52 +08:00
|
|
|
break;
|
2020-04-28 21:11:09 +08:00
|
|
|
}
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (FormatTok->isOneOf(Keywords.kw_get, Keywords.kw_set) &&
|
|
|
|
!IsTrivialPropertyAccessor) {
|
|
|
|
// Non-trivial get/set needs to be on its own line.
|
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
} while (!eof());
|
2020-04-23 18:38:52 +08:00
|
|
|
|
2020-04-28 21:11:09 +08:00
|
|
|
// Unreachable for well-formed code (paired '{' and '}').
|
2020-04-23 18:38:52 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-23 15:29:06 +08:00
|
|
|
bool UnwrappedLineParser::tryToParseLambda() {
|
2017-03-31 21:30:24 +08:00
|
|
|
if (!Style.isCpp()) {
|
2015-06-02 23:31:37 +08:00
|
|
|
nextToken();
|
|
|
|
return false;
|
|
|
|
}
|
2013-09-05 17:29:45 +08:00
|
|
|
assert(FormatTok->is(tok::l_square));
|
|
|
|
FormatToken &LSquare = *FormatTok;
|
2013-09-05 18:04:31 +08:00
|
|
|
if (!tryToParseLambdaIntroducer())
|
2013-12-23 15:29:06 +08:00
|
|
|
return false;
|
2013-09-03 23:10:01 +08:00
|
|
|
|
2019-03-12 00:02:52 +08:00
|
|
|
bool SeenArrow = false;
|
|
|
|
|
2014-03-13 21:59:48 +08:00
|
|
|
while (FormatTok->isNot(tok::l_brace)) {
|
2014-01-16 17:11:55 +08:00
|
|
|
if (FormatTok->isSimpleTypeSpecifier()) {
|
|
|
|
nextToken();
|
|
|
|
continue;
|
|
|
|
}
|
2013-09-03 23:10:01 +08:00
|
|
|
switch (FormatTok->Tok.getKind()) {
|
2013-09-05 18:04:31 +08:00
|
|
|
case tok::l_brace:
|
|
|
|
break;
|
|
|
|
case tok::l_paren:
|
|
|
|
parseParens();
|
|
|
|
break;
|
2014-11-21 22:08:38 +08:00
|
|
|
case tok::amp:
|
|
|
|
case tok::star:
|
|
|
|
case tok::kw_const:
|
2014-12-08 21:22:37 +08:00
|
|
|
case tok::comma:
|
2014-01-16 17:11:55 +08:00
|
|
|
case tok::less:
|
|
|
|
case tok::greater:
|
2013-09-05 18:04:31 +08:00
|
|
|
case tok::identifier:
|
2015-08-13 21:37:08 +08:00
|
|
|
case tok::numeric_constant:
|
2014-02-11 18:16:55 +08:00
|
|
|
case tok::coloncolon:
|
2019-09-13 21:18:55 +08:00
|
|
|
case tok::kw_class:
|
2013-09-05 18:04:31 +08:00
|
|
|
case tok::kw_mutable:
|
2019-01-30 21:54:32 +08:00
|
|
|
case tok::kw_noexcept:
|
2019-09-13 21:18:55 +08:00
|
|
|
case tok::kw_template:
|
|
|
|
case tok::kw_typename:
|
2019-03-12 00:02:52 +08:00
|
|
|
nextToken();
|
|
|
|
break;
|
2019-03-06 03:27:24 +08:00
|
|
|
// Specialization of a template with an integer parameter can contain
|
|
|
|
// arithmetic, logical, comparison and ternary operators.
|
2019-03-12 00:02:52 +08:00
|
|
|
//
|
|
|
|
// FIXME: This also accepts sequences of operators that are not in the scope
|
|
|
|
// of a template argument list.
|
|
|
|
//
|
|
|
|
// In a C++ lambda a template type can only occur after an arrow. We use
|
|
|
|
// this as an heuristic to distinguish between Objective-C expressions
|
|
|
|
// followed by an `a->b` expression, such as:
|
|
|
|
// ([obj func:arg] + a->b)
|
|
|
|
// Otherwise the code below would parse as a lambda.
|
2019-09-13 21:18:55 +08:00
|
|
|
//
|
|
|
|
// FIXME: This heuristic is incorrect for C++20 generic lambdas with
|
|
|
|
// explicit template lists: []<bool b = true && false>(U &&u){}
|
2019-03-06 03:27:24 +08:00
|
|
|
case tok::plus:
|
|
|
|
case tok::minus:
|
|
|
|
case tok::exclaim:
|
|
|
|
case tok::tilde:
|
|
|
|
case tok::slash:
|
|
|
|
case tok::percent:
|
|
|
|
case tok::lessless:
|
|
|
|
case tok::pipe:
|
|
|
|
case tok::pipepipe:
|
|
|
|
case tok::ampamp:
|
|
|
|
case tok::caret:
|
|
|
|
case tok::equalequal:
|
|
|
|
case tok::exclaimequal:
|
|
|
|
case tok::greaterequal:
|
|
|
|
case tok::lessequal:
|
|
|
|
case tok::question:
|
|
|
|
case tok::colon:
|
2020-04-30 18:02:42 +08:00
|
|
|
case tok::ellipsis:
|
2019-03-06 06:20:25 +08:00
|
|
|
case tok::kw_true:
|
|
|
|
case tok::kw_false:
|
2019-03-12 00:02:52 +08:00
|
|
|
if (SeenArrow) {
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
2014-01-16 17:11:55 +08:00
|
|
|
case tok::arrow:
|
2019-02-08 23:55:18 +08:00
|
|
|
// This might or might not actually be a lambda arrow (this could be an
|
|
|
|
// ObjC method invocation followed by a dereferencing arrow). We might
|
|
|
|
// reset this back to TT_Unknown in TokenAnnotator.
|
2015-06-05 21:18:09 +08:00
|
|
|
FormatTok->Type = TT_LambdaArrow;
|
2019-03-12 00:02:52 +08:00
|
|
|
SeenArrow = true;
|
2013-09-05 18:04:31 +08:00
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
default:
|
2013-12-23 15:29:06 +08:00
|
|
|
return true;
|
2013-09-03 23:10:01 +08:00
|
|
|
}
|
|
|
|
}
|
2019-03-27 04:18:14 +08:00
|
|
|
FormatTok->Type = TT_LambdaLBrace;
|
2013-09-05 17:29:45 +08:00
|
|
|
LSquare.Type = TT_LambdaLSquare;
|
2013-09-04 21:25:30 +08:00
|
|
|
parseChildBlock();
|
2013-12-23 15:29:06 +08:00
|
|
|
return true;
|
2013-09-03 23:10:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
|
2017-09-20 17:51:03 +08:00
|
|
|
const FormatToken *Previous = FormatTok->Previous;
|
2017-09-19 17:59:30 +08:00
|
|
|
if (Previous &&
|
|
|
|
(Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
|
2018-04-11 22:51:54 +08:00
|
|
|
tok::kw_delete, tok::l_square) ||
|
2017-09-20 17:51:03 +08:00
|
|
|
FormatTok->isCppStructuredBinding(Style) || Previous->closesScope() ||
|
|
|
|
Previous->isSimpleTypeSpecifier())) {
|
2013-09-03 23:10:01 +08:00
|
|
|
nextToken();
|
2017-09-19 17:59:30 +08:00
|
|
|
return false;
|
2013-09-03 23:10:01 +08:00
|
|
|
}
|
2017-09-19 17:59:30 +08:00
|
|
|
nextToken();
|
2018-04-11 22:51:54 +08:00
|
|
|
if (FormatTok->is(tok::l_square)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-09-19 17:59:30 +08:00
|
|
|
parseSquare(/*LambdaIntroducer=*/true);
|
|
|
|
return true;
|
2013-09-03 23:10:01 +08:00
|
|
|
}
|
|
|
|
|
2014-05-08 17:25:39 +08:00
|
|
|
void UnwrappedLineParser::tryToParseJSFunction() {
|
2016-05-29 22:41:07 +08:00
|
|
|
assert(FormatTok->is(Keywords.kw_function) ||
|
|
|
|
FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function));
|
2016-04-25 06:05:09 +08:00
|
|
|
if (FormatTok->is(Keywords.kw_async))
|
|
|
|
nextToken();
|
|
|
|
// Consume "function".
|
2014-05-08 17:25:39 +08:00
|
|
|
nextToken();
|
2014-06-13 15:02:04 +08:00
|
|
|
|
2016-11-01 14:22:59 +08:00
|
|
|
// Consume * (generator function). Treat it like C++'s overloaded operators.
|
|
|
|
if (FormatTok->is(tok::star)) {
|
|
|
|
FormatTok->Type = TT_OverloadedOperator;
|
2016-04-25 06:05:09 +08:00
|
|
|
nextToken();
|
2016-11-01 14:22:59 +08:00
|
|
|
}
|
2016-04-25 06:05:09 +08:00
|
|
|
|
2014-06-13 15:02:04 +08:00
|
|
|
// Consume function name.
|
|
|
|
if (FormatTok->is(tok::identifier))
|
2015-02-20 00:14:18 +08:00
|
|
|
nextToken();
|
2014-06-13 15:02:04 +08:00
|
|
|
|
2014-05-08 17:25:39 +08:00
|
|
|
if (FormatTok->isNot(tok::l_paren))
|
|
|
|
return;
|
2015-05-21 20:23:34 +08:00
|
|
|
|
|
|
|
// Parse formal parameter list.
|
2015-05-31 16:51:54 +08:00
|
|
|
parseParens();
|
2015-05-21 20:23:34 +08:00
|
|
|
|
|
|
|
if (FormatTok->is(tok::colon)) {
|
|
|
|
// Parse a type definition.
|
2014-05-08 17:25:39 +08:00
|
|
|
nextToken();
|
2015-05-21 20:23:34 +08:00
|
|
|
|
|
|
|
// Eat the type declaration. For braced inline object types, balance braces,
|
|
|
|
// otherwise just parse until finding an l_brace for the function body.
|
2015-05-31 16:51:54 +08:00
|
|
|
if (FormatTok->is(tok::l_brace))
|
|
|
|
tryToParseBracedList();
|
|
|
|
else
|
2017-01-04 21:36:43 +08:00
|
|
|
while (!FormatTok->isOneOf(tok::l_brace, tok::semi) && !eof())
|
2015-05-21 20:23:34 +08:00
|
|
|
nextToken();
|
2014-05-08 17:25:39 +08:00
|
|
|
}
|
2015-05-21 20:23:34 +08:00
|
|
|
|
2017-01-04 21:36:43 +08:00
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
return;
|
|
|
|
|
2014-05-08 17:25:39 +08:00
|
|
|
parseChildBlock();
|
|
|
|
}
|
|
|
|
|
2015-05-18 22:49:19 +08:00
|
|
|
bool UnwrappedLineParser::tryToParseBracedList() {
|
2013-07-09 17:06:29 +08:00
|
|
|
if (FormatTok->BlockKind == BK_Unknown)
|
2015-05-18 22:49:19 +08:00
|
|
|
calculateBraceTypes();
|
2013-07-09 17:06:29 +08:00
|
|
|
assert(FormatTok->BlockKind != BK_Unknown);
|
|
|
|
if (FormatTok->BlockKind == BK_Block)
|
2013-05-23 17:41:43 +08:00
|
|
|
return false;
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2013-05-23 17:41:43 +08:00
|
|
|
parseBracedList();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-27 21:43:07 +08:00
|
|
|
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
|
2020-05-01 00:11:54 +08:00
|
|
|
bool IsEnum,
|
2017-06-27 21:43:07 +08:00
|
|
|
tok::TokenKind ClosingBraceKind) {
|
2013-09-13 17:20:45 +08:00
|
|
|
bool HasError = false;
|
2020-04-28 03:41:01 +08:00
|
|
|
|
2013-04-10 17:52:05 +08:00
|
|
|
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
|
|
|
|
// replace this by using parseAssigmentExpression() inside.
|
2013-01-10 19:52:21 +08:00
|
|
|
do {
|
2020-03-04 20:13:33 +08:00
|
|
|
if (Style.isCSharp()) {
|
|
|
|
if (FormatTok->is(TT_JsFatArrow)) {
|
|
|
|
nextToken();
|
|
|
|
// Fat arrows can be followed by simple expressions or by child blocks
|
|
|
|
// in curly braces.
|
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
parseChildBlock();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-21 20:23:34 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
2016-05-29 22:41:07 +08:00
|
|
|
if (FormatTok->is(Keywords.kw_function) ||
|
|
|
|
FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
|
2015-05-21 20:23:34 +08:00
|
|
|
tryToParseJSFunction();
|
|
|
|
continue;
|
2015-05-31 16:51:54 +08:00
|
|
|
}
|
|
|
|
if (FormatTok->is(TT_JsFatArrow)) {
|
2015-05-21 20:23:34 +08:00
|
|
|
nextToken();
|
|
|
|
// Fat arrows can be followed by simple expressions or by child blocks
|
|
|
|
// in curly braces.
|
2015-06-17 21:08:06 +08:00
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
2015-05-21 20:23:34 +08:00
|
|
|
parseChildBlock();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-02-08 00:33:13 +08:00
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
// Could be a method inside of a braced list `{a() { return 1; }}`.
|
|
|
|
if (tryToParseBracedList())
|
|
|
|
continue;
|
|
|
|
parseChildBlock();
|
|
|
|
}
|
2014-05-08 17:25:39 +08:00
|
|
|
}
|
2017-06-27 21:43:07 +08:00
|
|
|
if (FormatTok->Tok.getKind() == ClosingBraceKind) {
|
2020-05-01 00:11:54 +08:00
|
|
|
if (IsEnum && !Style.AllowShortEnumsOnASingleLine)
|
|
|
|
addUnwrappedLine();
|
2017-06-27 21:43:07 +08:00
|
|
|
nextToken();
|
|
|
|
return !HasError;
|
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
switch (FormatTok->Tok.getKind()) {
|
2013-09-04 21:25:30 +08:00
|
|
|
case tok::caret:
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
parseChildBlock();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case tok::l_square:
|
2020-03-10 01:33:53 +08:00
|
|
|
if (Style.isCSharp())
|
|
|
|
parseSquare();
|
|
|
|
else
|
|
|
|
tryToParseLambda();
|
2013-09-04 21:25:30 +08:00
|
|
|
break;
|
2015-06-30 19:32:22 +08:00
|
|
|
case tok::l_paren:
|
|
|
|
parseParens();
|
2015-03-31 22:34:15 +08:00
|
|
|
// JavaScript can just have free standing methods and getters/setters in
|
|
|
|
// object literals. Detect them by a "{" following ")".
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
if (FormatTok->is(tok::l_brace))
|
|
|
|
parseChildBlock();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2017-02-08 00:33:13 +08:00
|
|
|
case tok::l_brace:
|
|
|
|
// Assume there are no blocks inside a braced init list apart
|
|
|
|
// from the ones we explicitly parse out (like lambdas).
|
|
|
|
FormatTok->BlockKind = BK_BracedInit;
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2017-02-08 00:33:13 +08:00
|
|
|
parseBracedList();
|
|
|
|
break;
|
2017-08-03 21:43:45 +08:00
|
|
|
case tok::less:
|
|
|
|
if (Style.Language == FormatStyle::LK_Proto) {
|
|
|
|
nextToken();
|
2020-05-01 05:34:49 +08:00
|
|
|
parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum*/false,
|
2017-08-03 21:43:45 +08:00
|
|
|
/*ClosingBraceKind=*/tok::greater);
|
|
|
|
} else {
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
break;
|
2013-04-10 17:52:05 +08:00
|
|
|
case tok::semi:
|
2016-01-09 23:56:28 +08:00
|
|
|
// JavaScript (or more precisely TypeScript) can have semicolons in braced
|
|
|
|
// lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
|
|
|
|
// used for error recovery if we have otherwise determined that this is
|
|
|
|
// a braced list.
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript) {
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
2013-09-13 17:20:45 +08:00
|
|
|
HasError = true;
|
|
|
|
if (!ContinueOnSemicolons)
|
|
|
|
return !HasError;
|
|
|
|
nextToken();
|
|
|
|
break;
|
2013-04-10 17:52:05 +08:00
|
|
|
case tok::comma:
|
|
|
|
nextToken();
|
2020-05-01 00:11:54 +08:00
|
|
|
if (IsEnum && !Style.AllowShortEnumsOnASingleLine)
|
|
|
|
addUnwrappedLine();
|
2013-04-10 17:52:05 +08:00
|
|
|
break;
|
2012-12-04 22:46:19 +08:00
|
|
|
default:
|
|
|
|
nextToken();
|
|
|
|
break;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
} while (!eof());
|
2013-09-13 17:20:45 +08:00
|
|
|
return false;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parseParens() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::l_paren) && "'(' expected.");
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
|
|
|
do {
|
2013-05-28 19:55:06 +08:00
|
|
|
switch (FormatTok->Tok.getKind()) {
|
2012-12-04 02:12:45 +08:00
|
|
|
case tok::l_paren:
|
|
|
|
parseParens();
|
2015-01-05 04:40:51 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_brace))
|
|
|
|
parseChildBlock();
|
2012-12-04 02:12:45 +08:00
|
|
|
break;
|
|
|
|
case tok::r_paren:
|
|
|
|
nextToken();
|
|
|
|
return;
|
2013-05-31 22:56:29 +08:00
|
|
|
case tok::r_brace:
|
|
|
|
// A "}" inside parenthesis is an error if there wasn't a matching "{".
|
|
|
|
return;
|
2013-09-05 18:04:31 +08:00
|
|
|
case tok::l_square:
|
|
|
|
tryToParseLambda();
|
|
|
|
break;
|
2015-01-05 04:40:51 +08:00
|
|
|
case tok::l_brace:
|
2015-05-18 20:52:00 +08:00
|
|
|
if (!tryToParseBracedList())
|
2013-09-04 21:34:14 +08:00
|
|
|
parseChildBlock();
|
2013-01-10 19:52:21 +08:00
|
|
|
break;
|
2013-02-11 04:35:35 +08:00
|
|
|
case tok::at:
|
|
|
|
nextToken();
|
2017-07-03 23:05:14 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
|
|
|
nextToken();
|
2013-02-11 04:35:35 +08:00
|
|
|
parseBracedList();
|
2017-07-03 23:05:14 +08:00
|
|
|
}
|
2013-02-11 04:35:35 +08:00
|
|
|
break;
|
2017-02-07 22:05:30 +08:00
|
|
|
case tok::kw_class:
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript)
|
|
|
|
parseRecord(/*ParseAsExpr=*/true);
|
|
|
|
else
|
|
|
|
nextToken();
|
|
|
|
break;
|
2014-09-05 16:42:27 +08:00
|
|
|
case tok::identifier:
|
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
2016-05-29 22:41:07 +08:00
|
|
|
(FormatTok->is(Keywords.kw_function) ||
|
|
|
|
FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)))
|
2014-09-05 16:42:27 +08:00
|
|
|
tryToParseJSFunction();
|
|
|
|
else
|
|
|
|
nextToken();
|
|
|
|
break;
|
2012-12-04 02:12:45 +08:00
|
|
|
default:
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2017-09-19 17:59:30 +08:00
|
|
|
void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
|
|
|
|
if (!LambdaIntroducer) {
|
|
|
|
assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
|
|
|
|
if (tryToParseLambda())
|
|
|
|
return;
|
|
|
|
}
|
2013-12-23 15:29:06 +08:00
|
|
|
do {
|
|
|
|
switch (FormatTok->Tok.getKind()) {
|
|
|
|
case tok::l_paren:
|
|
|
|
parseParens();
|
|
|
|
break;
|
|
|
|
case tok::r_square:
|
|
|
|
nextToken();
|
|
|
|
return;
|
|
|
|
case tok::r_brace:
|
|
|
|
// A "}" inside parenthesis is an error if there wasn't a matching "{".
|
|
|
|
return;
|
|
|
|
case tok::l_square:
|
|
|
|
parseSquare();
|
|
|
|
break;
|
|
|
|
case tok::l_brace: {
|
2015-05-18 20:52:00 +08:00
|
|
|
if (!tryToParseBracedList())
|
2013-12-23 15:29:06 +08:00
|
|
|
parseChildBlock();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case tok::at:
|
|
|
|
nextToken();
|
2017-07-03 23:05:14 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
|
|
|
nextToken();
|
2013-12-23 15:29:06 +08:00
|
|
|
parseBracedList();
|
2017-07-03 23:05:14 +08:00
|
|
|
}
|
2013-12-23 15:29:06 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nextToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2012-12-04 02:12:45 +08:00
|
|
|
void UnwrappedLineParser::parseIfThenElse() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2019-07-27 10:41:40 +08:00
|
|
|
if (FormatTok->Tok.isOneOf(tok::kw_constexpr, tok::identifier))
|
2017-06-19 15:40:49 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_paren))
|
2013-01-12 02:28:36 +08:00
|
|
|
parseParens();
|
2012-12-04 02:12:45 +08:00
|
|
|
bool NeedsUnwrappedLine = false;
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2013-12-12 17:49:52 +08:00
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2015-09-29 22:57:55 +08:00
|
|
|
if (Style.BraceWrapping.BeforeElse)
|
2013-08-03 05:31:59 +08:00
|
|
|
addUnwrappedLine();
|
2015-09-29 22:57:55 +08:00
|
|
|
else
|
2013-08-03 05:31:59 +08:00
|
|
|
NeedsUnwrappedLine = true;
|
2012-12-04 02:12:45 +08:00
|
|
|
} else {
|
|
|
|
addUnwrappedLine();
|
2013-01-09 23:25:02 +08:00
|
|
|
++Line->Level;
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2013-01-09 23:25:02 +08:00
|
|
|
--Line->Level;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::kw_else)) {
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2013-12-12 17:49:52 +08:00
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2012-12-04 02:12:45 +08:00
|
|
|
addUnwrappedLine();
|
2013-05-28 19:55:06 +08:00
|
|
|
} else if (FormatTok->Tok.is(tok::kw_if)) {
|
2012-12-04 02:12:45 +08:00
|
|
|
parseIfThenElse();
|
|
|
|
} else {
|
|
|
|
addUnwrappedLine();
|
2013-01-09 23:25:02 +08:00
|
|
|
++Line->Level;
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2016-05-19 14:30:48 +08:00
|
|
|
if (FormatTok->is(tok::eof))
|
|
|
|
addUnwrappedLine();
|
2013-01-09 23:25:02 +08:00
|
|
|
--Line->Level;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
} else if (NeedsUnwrappedLine) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-08 19:58:24 +08:00
|
|
|
void UnwrappedLineParser::parseTryCatch() {
|
2015-02-04 23:26:27 +08:00
|
|
|
assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected");
|
2014-05-08 19:58:24 +08:00
|
|
|
nextToken();
|
|
|
|
bool NeedsUnwrappedLine = false;
|
|
|
|
if (FormatTok->is(tok::colon)) {
|
|
|
|
// We are in a function try block, what comes is an initializer list.
|
|
|
|
nextToken();
|
2020-02-20 06:58:54 +08:00
|
|
|
|
|
|
|
// In case identifiers were removed by clang-tidy, what might follow is
|
|
|
|
// multiple commas in sequence - before the first identifier.
|
|
|
|
while (FormatTok->is(tok::comma))
|
|
|
|
nextToken();
|
|
|
|
|
2014-05-08 19:58:24 +08:00
|
|
|
while (FormatTok->is(tok::identifier)) {
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::l_paren))
|
|
|
|
parseParens();
|
2020-02-20 06:58:54 +08:00
|
|
|
|
|
|
|
// In case identifiers were removed by clang-tidy, what might follow is
|
|
|
|
// multiple commas in sequence - after the first identifier.
|
|
|
|
while (FormatTok->is(tok::comma))
|
2014-05-08 19:58:24 +08:00
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 18:48:41 +08:00
|
|
|
// Parse try with resource.
|
|
|
|
if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) {
|
|
|
|
parseParens();
|
|
|
|
}
|
2014-05-08 19:58:24 +08:00
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2015-09-29 22:57:55 +08:00
|
|
|
if (Style.BraceWrapping.BeforeCatch) {
|
2014-05-08 19:58:24 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
} else {
|
|
|
|
NeedsUnwrappedLine = true;
|
|
|
|
}
|
|
|
|
} else if (!FormatTok->is(tok::kw_catch)) {
|
|
|
|
// The C++ standard requires a compound-statement after a try.
|
|
|
|
// If there's none, we try to assume there's a structuralElement
|
|
|
|
// and try to continue.
|
|
|
|
addUnwrappedLine();
|
|
|
|
++Line->Level;
|
|
|
|
parseStructuralElement();
|
|
|
|
--Line->Level;
|
|
|
|
}
|
2015-02-07 09:57:32 +08:00
|
|
|
while (1) {
|
|
|
|
if (FormatTok->is(tok::at))
|
|
|
|
nextToken();
|
|
|
|
if (!(FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except,
|
|
|
|
tok::kw___finally) ||
|
|
|
|
((Style.Language == FormatStyle::LK_Java ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript) &&
|
|
|
|
FormatTok->is(Keywords.kw_finally)) ||
|
|
|
|
(FormatTok->Tok.isObjCAtKeyword(tok::objc_catch) ||
|
|
|
|
FormatTok->Tok.isObjCAtKeyword(tok::objc_finally))))
|
|
|
|
break;
|
2014-05-08 19:58:24 +08:00
|
|
|
nextToken();
|
|
|
|
while (FormatTok->isNot(tok::l_brace)) {
|
|
|
|
if (FormatTok->is(tok::l_paren)) {
|
|
|
|
parseParens();
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-19 18:50:51 +08:00
|
|
|
if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof))
|
2014-05-08 19:58:24 +08:00
|
|
|
return;
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
NeedsUnwrappedLine = false;
|
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2015-09-29 22:57:55 +08:00
|
|
|
if (Style.BraceWrapping.BeforeCatch)
|
2014-05-08 19:58:24 +08:00
|
|
|
addUnwrappedLine();
|
2015-09-29 22:57:55 +08:00
|
|
|
else
|
2014-05-08 19:58:24 +08:00
|
|
|
NeedsUnwrappedLine = true;
|
|
|
|
}
|
2015-09-29 22:57:55 +08:00
|
|
|
if (NeedsUnwrappedLine)
|
2014-05-08 19:58:24 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
|
|
|
|
2012-12-07 02:03:27 +08:00
|
|
|
void UnwrappedLineParser::parseNamespace() {
|
2019-06-07 04:06:23 +08:00
|
|
|
assert(FormatTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) &&
|
|
|
|
"'namespace' expected");
|
2014-08-11 20:18:01 +08:00
|
|
|
|
|
|
|
const FormatToken &InitialToken = *FormatTok;
|
2012-12-07 02:03:27 +08:00
|
|
|
nextToken();
|
2019-06-07 04:06:23 +08:00
|
|
|
if (InitialToken.is(TT_NamespaceMacro)) {
|
|
|
|
parseParens();
|
|
|
|
} else {
|
2019-07-24 01:49:45 +08:00
|
|
|
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
|
|
|
|
tok::l_square)) {
|
|
|
|
if (FormatTok->is(tok::l_square))
|
|
|
|
parseSquare();
|
|
|
|
else
|
|
|
|
nextToken();
|
|
|
|
}
|
2019-06-07 04:06:23 +08:00
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2014-08-11 20:18:01 +08:00
|
|
|
if (ShouldBreakBeforeBrace(Style, InitialToken))
|
2013-05-13 20:51:40 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
|
2013-08-01 07:16:02 +08:00
|
|
|
bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All ||
|
|
|
|
(Style.NamespaceIndentation == FormatStyle::NI_Inner &&
|
|
|
|
DeclarationScopeStack.size() > 1);
|
|
|
|
parseBlock(/*MustBeDeclaration=*/true, AddLevel);
|
2013-02-07 00:08:09 +08:00
|
|
|
// Munch the semicolon after a namespace. This is more common than one would
|
2020-03-04 20:13:33 +08:00
|
|
|
// think. Putting the semicolon into its own line is very ugly.
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::semi))
|
2013-02-07 00:08:09 +08:00
|
|
|
nextToken();
|
2012-12-07 02:03:27 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
|
|
|
// FIXME: Add error handling.
|
|
|
|
}
|
|
|
|
|
2015-03-12 22:44:29 +08:00
|
|
|
void UnwrappedLineParser::parseNew() {
|
|
|
|
assert(FormatTok->is(tok::kw_new) && "'new' expected");
|
|
|
|
nextToken();
|
2020-03-04 20:13:33 +08:00
|
|
|
|
|
|
|
if (Style.isCSharp()) {
|
|
|
|
do {
|
|
|
|
if (FormatTok->is(tok::l_brace))
|
|
|
|
parseBracedList();
|
|
|
|
|
|
|
|
if (FormatTok->isOneOf(tok::semi, tok::comma))
|
|
|
|
return;
|
|
|
|
|
|
|
|
nextToken();
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2015-03-12 22:44:29 +08:00
|
|
|
if (Style.Language != FormatStyle::LK_Java)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// In Java, we can parse everything up to the parens, which aren't optional.
|
|
|
|
do {
|
|
|
|
// There should not be a ;, { or } before the new's open paren.
|
|
|
|
if (FormatTok->isOneOf(tok::semi, tok::l_brace, tok::r_brace))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Consume the parens.
|
|
|
|
if (FormatTok->is(tok::l_paren)) {
|
|
|
|
parseParens();
|
|
|
|
|
|
|
|
// If there is a class body of an anonymous class, consume that as child.
|
|
|
|
if (FormatTok->is(tok::l_brace))
|
|
|
|
parseChildBlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nextToken();
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2012-12-05 23:06:06 +08:00
|
|
|
void UnwrappedLineParser::parseForOrWhileLoop() {
|
2015-05-04 17:22:29 +08:00
|
|
|
assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) &&
|
2014-04-01 20:55:11 +08:00
|
|
|
"'for', 'while' or foreach macro expected");
|
2012-12-05 23:06:06 +08:00
|
|
|
nextToken();
|
2017-05-19 05:19:29 +08:00
|
|
|
// JS' for await ( ...
|
2017-05-16 03:33:20 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
2017-05-19 05:19:29 +08:00
|
|
|
FormatTok->is(Keywords.kw_await))
|
2017-05-16 03:33:20 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_paren))
|
2013-01-12 03:23:05 +08:00
|
|
|
parseParens();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2013-12-12 17:49:52 +08:00
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2012-12-05 23:06:06 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
} else {
|
|
|
|
addUnwrappedLine();
|
2013-01-09 23:25:02 +08:00
|
|
|
++Line->Level;
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2013-01-09 23:25:02 +08:00
|
|
|
--Line->Level;
|
2012-12-05 23:06:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-04 02:12:45 +08:00
|
|
|
void UnwrappedLineParser::parseDoWhile() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected");
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2013-12-12 17:49:52 +08:00
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2015-09-29 22:57:55 +08:00
|
|
|
if (Style.BraceWrapping.IndentBraces)
|
2013-12-12 17:49:52 +08:00
|
|
|
addUnwrappedLine();
|
2012-12-04 02:12:45 +08:00
|
|
|
} else {
|
|
|
|
addUnwrappedLine();
|
2013-01-09 23:25:02 +08:00
|
|
|
++Line->Level;
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2013-01-09 23:25:02 +08:00
|
|
|
--Line->Level;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2012-12-04 23:40:36 +08:00
|
|
|
// FIXME: Add error handling.
|
2013-05-28 19:55:06 +08:00
|
|
|
if (!FormatTok->Tok.is(tok::kw_while)) {
|
2012-12-04 23:40:36 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2019-09-12 18:07:14 +08:00
|
|
|
void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) {
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2013-01-09 23:25:02 +08:00
|
|
|
unsigned OldLineLevel = Line->Level;
|
2013-03-20 18:23:53 +08:00
|
|
|
if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
|
2013-01-09 23:25:02 +08:00
|
|
|
--Line->Level;
|
2019-09-12 18:07:14 +08:00
|
|
|
if (LeftAlignLabel)
|
|
|
|
Line->Level = 0;
|
2020-01-19 23:52:26 +08:00
|
|
|
if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() &&
|
|
|
|
FormatTok->Tok.is(tok::l_brace)) {
|
2019-04-09 07:36:25 +08:00
|
|
|
CompoundStatementIndenter Indenter(this, Line->Level,
|
|
|
|
Style.BraceWrapping.AfterCaseLabel,
|
|
|
|
Style.BraceWrapping.IndentBraces);
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2013-08-03 05:31:59 +08:00
|
|
|
if (FormatTok->Tok.is(tok::kw_break)) {
|
[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-04 02:42:31 +08:00
|
|
|
if (Style.BraceWrapping.AfterControlStatement ==
|
|
|
|
FormatStyle::BWACS_Always)
|
2013-08-03 05:31:59 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
parseStructuralElement();
|
|
|
|
}
|
2013-12-12 17:49:52 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
} else {
|
2015-05-06 23:19:47 +08:00
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
nextToken();
|
2013-12-12 17:49:52 +08:00
|
|
|
addUnwrappedLine();
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
2013-01-09 23:25:02 +08:00
|
|
|
Line->Level = OldLineLevel;
|
2016-04-07 00:41:39 +08:00
|
|
|
if (FormatTok->isNot(tok::l_brace)) {
|
2016-04-06 23:02:46 +08:00
|
|
|
parseStructuralElement();
|
2016-04-07 00:41:39 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parseCaseLabel() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::kw_case) && "'case' expected");
|
2012-12-04 02:12:45 +08:00
|
|
|
// FIXME: fix handling of complex expressions here.
|
|
|
|
do {
|
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
} while (!eof() && !FormatTok->Tok.is(tok::colon));
|
2012-12-04 02:12:45 +08:00
|
|
|
parseLabel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parseSwitch() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::kw_switch) && "'switch' expected");
|
2012-12-04 02:12:45 +08:00
|
|
|
nextToken();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_paren))
|
2013-01-12 03:23:05 +08:00
|
|
|
parseParens();
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2013-12-12 17:49:52 +08:00
|
|
|
CompoundStatementIndenter Indenter(this, Style, Line->Level);
|
2013-08-01 07:16:02 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
2012-12-04 02:12:45 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
} else {
|
|
|
|
addUnwrappedLine();
|
2013-07-25 19:31:57 +08:00
|
|
|
++Line->Level;
|
2013-01-07 22:56:16 +08:00
|
|
|
parseStructuralElement();
|
2013-07-25 19:31:57 +08:00
|
|
|
--Line->Level;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parseAccessSpecifier() {
|
|
|
|
nextToken();
|
2013-11-24 01:53:41 +08:00
|
|
|
// Understand Qt's slots.
|
2015-04-07 23:04:40 +08:00
|
|
|
if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots))
|
2013-11-24 01:53:41 +08:00
|
|
|
nextToken();
|
2012-12-11 00:34:48 +08:00
|
|
|
// Otherwise, we don't know what it is, and we'd better keep the next token.
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::colon))
|
2012-12-11 00:34:48 +08:00
|
|
|
nextToken();
|
2012-12-04 02:12:45 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
|
|
|
|
2015-12-29 16:54:23 +08:00
|
|
|
bool UnwrappedLineParser::parseEnum() {
|
2014-11-13 23:56:28 +08:00
|
|
|
// Won't be 'enum' for NS_ENUMs.
|
|
|
|
if (FormatTok->Tok.is(tok::kw_enum))
|
2014-11-20 06:38:18 +08:00
|
|
|
nextToken();
|
2014-11-13 23:56:28 +08:00
|
|
|
|
2015-12-29 16:54:23 +08:00
|
|
|
// In TypeScript, "enum" can also be used as property name, e.g. in interface
|
|
|
|
// declarations. An "enum" keyword followed by a colon would be a syntax
|
|
|
|
// error and thus assume it is just an identifier.
|
2016-02-03 13:33:44 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
FormatTok->isOneOf(tok::colon, tok::question))
|
2015-12-29 16:54:23 +08:00
|
|
|
return false;
|
|
|
|
|
2019-03-23 22:24:30 +08:00
|
|
|
// In protobuf, "enum" can be used as a field name.
|
|
|
|
if (Style.Language == FormatStyle::LK_Proto && FormatTok->is(tok::equal))
|
|
|
|
return false;
|
|
|
|
|
2013-08-20 20:42:50 +08:00
|
|
|
// Eat up enum class ...
|
2014-05-09 21:11:16 +08:00
|
|
|
if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct))
|
|
|
|
nextToken();
|
2015-06-19 16:17:32 +08:00
|
|
|
|
2013-09-07 05:32:35 +08:00
|
|
|
while (FormatTok->Tok.getIdentifierInfo() ||
|
2014-11-20 06:38:18 +08:00
|
|
|
FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less,
|
|
|
|
tok::greater, tok::comma, tok::question)) {
|
2013-01-22 03:17:52 +08:00
|
|
|
nextToken();
|
|
|
|
// We can have macros or attributes in between 'enum' and the enum name.
|
2014-11-20 06:38:18 +08:00
|
|
|
if (FormatTok->is(tok::l_paren))
|
2012-12-04 22:46:19 +08:00
|
|
|
parseParens();
|
2015-06-19 16:17:32 +08:00
|
|
|
if (FormatTok->is(tok::identifier)) {
|
2012-12-04 22:46:19 +08:00
|
|
|
nextToken();
|
2015-06-19 16:17:32 +08:00
|
|
|
// If there are two identifiers in a row, this is likely an elaborate
|
|
|
|
// return type. In Java, this can be "implements", etc.
|
2017-03-31 21:30:24 +08:00
|
|
|
if (Style.isCpp() && FormatTok->is(tok::identifier))
|
2015-12-29 16:54:23 +08:00
|
|
|
return false;
|
2015-06-19 16:17:32 +08:00
|
|
|
}
|
2013-01-22 03:17:52 +08:00
|
|
|
}
|
2014-11-13 23:56:28 +08:00
|
|
|
|
|
|
|
// Just a declaration or something is wrong.
|
2014-11-20 06:38:18 +08:00
|
|
|
if (FormatTok->isNot(tok::l_brace))
|
2015-12-29 16:54:23 +08:00
|
|
|
return true;
|
2014-11-13 23:56:28 +08:00
|
|
|
FormatTok->BlockKind = BK_Block;
|
|
|
|
|
|
|
|
if (Style.Language == FormatStyle::LK_Java) {
|
|
|
|
// Java enums are different.
|
|
|
|
parseJavaEnumBody();
|
2015-12-29 16:54:23 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (Style.Language == FormatStyle::LK_Proto) {
|
2015-07-16 22:25:43 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/true);
|
2015-12-29 16:54:23 +08:00
|
|
|
return true;
|
2013-01-22 03:17:52 +08:00
|
|
|
}
|
2014-11-13 23:56:28 +08:00
|
|
|
|
2020-05-01 00:11:54 +08:00
|
|
|
if (!Style.AllowShortEnumsOnASingleLine)
|
|
|
|
addUnwrappedLine();
|
2014-11-13 23:56:28 +08:00
|
|
|
// Parse enum body.
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2020-05-01 00:11:54 +08:00
|
|
|
if (!Style.AllowShortEnumsOnASingleLine) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
Line->Level += 1;
|
|
|
|
}
|
|
|
|
bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true,
|
|
|
|
/*IsEnum=*/true);
|
|
|
|
if (!Style.AllowShortEnumsOnASingleLine)
|
|
|
|
Line->Level -= 1;
|
2014-11-13 23:56:28 +08:00
|
|
|
if (HasError) {
|
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
2015-12-29 16:54:23 +08:00
|
|
|
return true;
|
2014-11-13 23:56:28 +08:00
|
|
|
|
2015-06-17 17:44:02 +08:00
|
|
|
// There is no addUnwrappedLine() here so that we fall through to parsing a
|
|
|
|
// structural element afterwards. Thus, in "enum A {} n, m;",
|
2013-01-22 03:17:52 +08:00
|
|
|
// "} n, m;" will end up in one unwrapped line.
|
2014-11-13 23:56:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parseJavaEnumBody() {
|
|
|
|
// Determine whether the enum is simple, i.e. does not have a semicolon or
|
|
|
|
// constants with class bodies. Simple enums can be formatted like braced
|
|
|
|
// lists, contracted to a single line, etc.
|
|
|
|
unsigned StoredPosition = Tokens->getPosition();
|
|
|
|
bool IsSimple = true;
|
|
|
|
FormatToken *Tok = Tokens->getNextToken();
|
|
|
|
while (Tok) {
|
|
|
|
if (Tok->is(tok::r_brace))
|
|
|
|
break;
|
|
|
|
if (Tok->isOneOf(tok::l_brace, tok::semi)) {
|
|
|
|
IsSimple = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// FIXME: This will also mark enums with braces in the arguments to enum
|
|
|
|
// constants as "not simple". This is probably fine in practice, though.
|
|
|
|
Tok = Tokens->getNextToken();
|
|
|
|
}
|
|
|
|
FormatTok = Tokens->setPosition(StoredPosition);
|
|
|
|
|
|
|
|
if (IsSimple) {
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2014-11-13 23:56:28 +08:00
|
|
|
parseBracedList();
|
2014-11-03 06:31:39 +08:00
|
|
|
addUnwrappedLine();
|
2014-11-13 23:56:28 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the body of a more complex enum.
|
|
|
|
// First add a line for everything up to the "{".
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
++Line->Level;
|
|
|
|
|
|
|
|
// Parse the enum constants.
|
|
|
|
while (FormatTok) {
|
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
// Parse the constant's class body.
|
|
|
|
parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
|
|
|
|
/*MunchSemi=*/false);
|
|
|
|
} else if (FormatTok->is(tok::l_paren)) {
|
|
|
|
parseParens();
|
|
|
|
} else if (FormatTok->is(tok::comma)) {
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
} else if (FormatTok->is(tok::semi)) {
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
break;
|
|
|
|
} else if (FormatTok->is(tok::r_brace)) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the class body after the enum's ";" if any.
|
|
|
|
parseLevel(/*HasOpeningBrace=*/true);
|
|
|
|
nextToken();
|
|
|
|
--Line->Level;
|
|
|
|
addUnwrappedLine();
|
2013-01-08 02:10:23 +08:00
|
|
|
}
|
|
|
|
|
2017-02-07 22:05:30 +08:00
|
|
|
void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
|
2014-08-11 20:18:01 +08:00
|
|
|
const FormatToken &InitialToken = *FormatTok;
|
2013-01-08 02:10:23 +08:00
|
|
|
nextToken();
|
2015-05-06 22:03:02 +08:00
|
|
|
|
|
|
|
// The actual identifier can be a nested name specifier, and in macros
|
|
|
|
// it is often token-pasted.
|
|
|
|
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::hashhash,
|
|
|
|
tok::kw___attribute, tok::kw___declspec,
|
|
|
|
tok::kw_alignas) ||
|
|
|
|
((Style.Language == FormatStyle::LK_Java ||
|
|
|
|
Style.Language == FormatStyle::LK_JavaScript) &&
|
|
|
|
FormatTok->isOneOf(tok::period, tok::comma))) {
|
2017-08-01 23:46:10 +08:00
|
|
|
if (Style.Language == FormatStyle::LK_JavaScript &&
|
|
|
|
FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
|
|
|
|
// JavaScript/TypeScript supports inline object types in
|
|
|
|
// extends/implements positions:
|
|
|
|
// class Foo implements {bar: number} { }
|
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
tryToParseBracedList();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2015-05-06 22:03:02 +08:00
|
|
|
bool IsNonMacroIdentifier =
|
|
|
|
FormatTok->is(tok::identifier) &&
|
|
|
|
FormatTok->TokenText != FormatTok->TokenText.upper();
|
2013-01-15 21:38:33 +08:00
|
|
|
nextToken();
|
|
|
|
// We can have macros or attributes in between 'class' and the class name.
|
2015-05-06 22:03:02 +08:00
|
|
|
if (!IsNonMacroIdentifier && FormatTok->Tok.is(tok::l_paren))
|
2013-01-15 21:38:33 +08:00
|
|
|
parseParens();
|
2015-05-06 22:03:02 +08:00
|
|
|
}
|
2013-01-15 21:38:33 +08:00
|
|
|
|
2015-05-06 22:03:02 +08:00
|
|
|
// Note that parsing away template declarations here leads to incorrectly
|
|
|
|
// accepting function declarations as record declarations.
|
|
|
|
// In general, we cannot solve this problem. Consider:
|
|
|
|
// class A<int> B() {}
|
|
|
|
// which can be a function definition or a class definition when B() is a
|
|
|
|
// macro. If we find enough real-world cases where this is a problem, we
|
|
|
|
// can parse for the 'template' keyword in the beginning of the statement,
|
|
|
|
// and thus rule out the record production in case there is no template
|
|
|
|
// (this would still leave us with an ambiguity between template function
|
|
|
|
// and class declarations).
|
2015-05-18 20:52:00 +08:00
|
|
|
if (FormatTok->isOneOf(tok::colon, tok::less)) {
|
|
|
|
while (!eof()) {
|
2015-05-18 22:49:19 +08:00
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
calculateBraceTypes(/*ExpectClassBody=*/true);
|
|
|
|
if (!tryToParseBracedList())
|
|
|
|
break;
|
|
|
|
}
|
2015-05-06 22:03:02 +08:00
|
|
|
if (FormatTok->Tok.is(tok::semi))
|
|
|
|
return;
|
2020-04-01 01:41:39 +08:00
|
|
|
if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
|
|
|
|
addUnwrappedLine();
|
|
|
|
nextToken();
|
|
|
|
parseCSharpGenericTypeConstraint();
|
|
|
|
break;
|
|
|
|
}
|
2015-05-06 22:03:02 +08:00
|
|
|
nextToken();
|
2013-01-08 02:10:23 +08:00
|
|
|
}
|
2013-01-15 21:38:33 +08:00
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2017-02-07 22:05:30 +08:00
|
|
|
if (ParseAsExpr) {
|
|
|
|
parseChildBlock();
|
|
|
|
} else {
|
|
|
|
if (ShouldBreakBeforeBrace(Style, InitialToken))
|
|
|
|
addUnwrappedLine();
|
2013-05-13 20:51:40 +08:00
|
|
|
|
2017-02-07 22:05:30 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
|
|
|
|
/*MunchSemi=*/false);
|
|
|
|
}
|
2013-05-13 20:51:40 +08:00
|
|
|
}
|
2015-06-17 17:44:02 +08:00
|
|
|
// There is no addUnwrappedLine() here so that we fall through to parsing a
|
|
|
|
// structural element afterwards. Thus, in "class A {} n, m;",
|
|
|
|
// "} n, m;" will end up in one unwrapped line.
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
[clang-format/ObjC] Correctly parse Objective-C methods with 'class' in name
Summary:
Please take a close look at this CL. I haven't touched much of
`UnwrappedLineParser` before, so I may have gotten things wrong.
Previously, clang-format would incorrectly format the following:
```
@implementation Foo
- (Class)class {
}
- (void)foo {
}
@end
```
as:
```
@implementation Foo
- (Class)class {
}
- (void)foo {
}
@end
```
The problem is whenever `UnwrappedLineParser::parseStructuralElement()`
sees any of the keywords `class`, `struct`, or `enum`, it calls
`parseRecord()` to parse them as a C/C++ record.
This causes subsequent lines to be parsed incorrectly, which
causes them to be indented incorrectly.
In Objective-C/Objective-C++, these keywords are valid selector
components.
This diff fixes the issue by explicitly handling `+` and `-` lines
inside `@implementation` / `@interface` / `@protocol` blocks
and parsing them as Objective-C methods.
Test Plan: New tests added. Ran tests with:
make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests
Reviewers: jolesiak, klimek
Reviewed By: jolesiak, klimek
Subscribers: klimek, cfe-commits, Wizard
Differential Revision: https://reviews.llvm.org/D47095
llvm-svn: 333553
2018-05-30 23:21:38 +08:00
|
|
|
void UnwrappedLineParser::parseObjCMethod() {
|
|
|
|
assert(FormatTok->Tok.isOneOf(tok::l_paren, tok::identifier) &&
|
|
|
|
"'(' or identifier expected.");
|
|
|
|
do {
|
|
|
|
if (FormatTok->Tok.is(tok::semi)) {
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
} else if (FormatTok->Tok.is(tok::l_brace)) {
|
2018-10-13 03:43:01 +08:00
|
|
|
if (Style.BraceWrapping.AfterFunction)
|
|
|
|
addUnwrappedLine();
|
[clang-format/ObjC] Correctly parse Objective-C methods with 'class' in name
Summary:
Please take a close look at this CL. I haven't touched much of
`UnwrappedLineParser` before, so I may have gotten things wrong.
Previously, clang-format would incorrectly format the following:
```
@implementation Foo
- (Class)class {
}
- (void)foo {
}
@end
```
as:
```
@implementation Foo
- (Class)class {
}
- (void)foo {
}
@end
```
The problem is whenever `UnwrappedLineParser::parseStructuralElement()`
sees any of the keywords `class`, `struct`, or `enum`, it calls
`parseRecord()` to parse them as a C/C++ record.
This causes subsequent lines to be parsed incorrectly, which
causes them to be indented incorrectly.
In Objective-C/Objective-C++, these keywords are valid selector
components.
This diff fixes the issue by explicitly handling `+` and `-` lines
inside `@implementation` / `@interface` / `@protocol` blocks
and parsing them as Objective-C methods.
Test Plan: New tests added. Ran tests with:
make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests
Reviewers: jolesiak, klimek
Reviewed By: jolesiak, klimek
Subscribers: klimek, cfe-commits, Wizard
Differential Revision: https://reviews.llvm.org/D47095
llvm-svn: 333553
2018-05-30 23:21:38 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
|
|
|
addUnwrappedLine();
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
nextToken();
|
|
|
|
}
|
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2013-01-10 05:15:03 +08:00
|
|
|
void UnwrappedLineParser::parseObjCProtocolList() {
|
2013-05-28 19:55:06 +08:00
|
|
|
assert(FormatTok->Tok.is(tok::less) && "'<' expected.");
|
[clang-format] Support lightweight Objective-C generics
Summary:
Previously, `clang-format` didn't understand lightweight
Objective-C generics, which have the form:
```
@interface Foo <KeyType,
ValueTypeWithConstraint : Foo,
AnotherValueTypeWithGenericConstraint: Bar<Baz>, ... > ...
```
The lightweight generic specifier list appears before the base
class, if present, but because it starts with < like the protocol
specifier list, `UnwrappedLineParser` was getting confused and
failed to parse interfaces with both generics and protocol lists:
```
@interface Foo <KeyType> : NSObject <NSCopying>
```
Since the parsed line would be incomplete, the format result
would be very confused (e.g., https://bugs.llvm.org/show_bug.cgi?id=24381).
This fixes the issue by explicitly parsing the ObjC lightweight
generic conformance list, so the line is fully parsed.
Fixes: https://bugs.llvm.org/show_bug.cgi?id=24381
Test Plan: New tests added. Ran tests with:
% make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D45185
llvm-svn: 329298
2018-04-05 23:26:25 +08:00
|
|
|
do {
|
2013-01-10 05:15:03 +08:00
|
|
|
nextToken();
|
[clang-format] Support lightweight Objective-C generics
Summary:
Previously, `clang-format` didn't understand lightweight
Objective-C generics, which have the form:
```
@interface Foo <KeyType,
ValueTypeWithConstraint : Foo,
AnotherValueTypeWithGenericConstraint: Bar<Baz>, ... > ...
```
The lightweight generic specifier list appears before the base
class, if present, but because it starts with < like the protocol
specifier list, `UnwrappedLineParser` was getting confused and
failed to parse interfaces with both generics and protocol lists:
```
@interface Foo <KeyType> : NSObject <NSCopying>
```
Since the parsed line would be incomplete, the format result
would be very confused (e.g., https://bugs.llvm.org/show_bug.cgi?id=24381).
This fixes the issue by explicitly parsing the ObjC lightweight
generic conformance list, so the line is fully parsed.
Fixes: https://bugs.llvm.org/show_bug.cgi?id=24381
Test Plan: New tests added. Ran tests with:
% make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D45185
llvm-svn: 329298
2018-04-05 23:26:25 +08:00
|
|
|
// Early exit in case someone forgot a close angle.
|
|
|
|
if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
|
|
|
|
FormatTok->Tok.isObjCAtKeyword(tok::objc_end))
|
|
|
|
return;
|
|
|
|
} while (!eof() && FormatTok->Tok.isNot(tok::greater));
|
2013-01-10 05:15:03 +08:00
|
|
|
nextToken(); // Skip '>'.
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnwrappedLineParser::parseObjCUntilAtEnd() {
|
|
|
|
do {
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) {
|
2013-01-10 05:15:03 +08:00
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
break;
|
|
|
|
}
|
2013-08-28 16:04:23 +08:00
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
parseBlock(/*MustBeDeclaration=*/false);
|
|
|
|
// In ObjC interfaces, nothing should be following the "}".
|
|
|
|
addUnwrappedLine();
|
2014-01-08 23:59:42 +08:00
|
|
|
} else if (FormatTok->is(tok::r_brace)) {
|
|
|
|
// Ignore stray "}". parseStructuralElement doesn't consume them.
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
[clang-format/ObjC] Correctly parse Objective-C methods with 'class' in name
Summary:
Please take a close look at this CL. I haven't touched much of
`UnwrappedLineParser` before, so I may have gotten things wrong.
Previously, clang-format would incorrectly format the following:
```
@implementation Foo
- (Class)class {
}
- (void)foo {
}
@end
```
as:
```
@implementation Foo
- (Class)class {
}
- (void)foo {
}
@end
```
The problem is whenever `UnwrappedLineParser::parseStructuralElement()`
sees any of the keywords `class`, `struct`, or `enum`, it calls
`parseRecord()` to parse them as a C/C++ record.
This causes subsequent lines to be parsed incorrectly, which
causes them to be indented incorrectly.
In Objective-C/Objective-C++, these keywords are valid selector
components.
This diff fixes the issue by explicitly handling `+` and `-` lines
inside `@implementation` / `@interface` / `@protocol` blocks
and parsing them as Objective-C methods.
Test Plan: New tests added. Ran tests with:
make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests
Reviewers: jolesiak, klimek
Reviewed By: jolesiak, klimek
Subscribers: klimek, cfe-commits, Wizard
Differential Revision: https://reviews.llvm.org/D47095
llvm-svn: 333553
2018-05-30 23:21:38 +08:00
|
|
|
} else if (FormatTok->isOneOf(tok::minus, tok::plus)) {
|
|
|
|
nextToken();
|
|
|
|
parseObjCMethod();
|
2013-08-28 16:04:23 +08:00
|
|
|
} else {
|
|
|
|
parseStructuralElement();
|
|
|
|
}
|
2013-01-10 05:15:03 +08:00
|
|
|
} while (!eof());
|
|
|
|
}
|
|
|
|
|
2013-01-10 07:25:37 +08:00
|
|
|
void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
|
2018-01-24 01:10:25 +08:00
|
|
|
assert(FormatTok->Tok.getObjCKeywordID() == tok::objc_interface ||
|
|
|
|
FormatTok->Tok.getObjCKeywordID() == tok::objc_implementation);
|
2013-01-10 04:25:35 +08:00
|
|
|
nextToken();
|
2013-03-20 20:37:50 +08:00
|
|
|
nextToken(); // interface name
|
2013-01-10 04:25:35 +08:00
|
|
|
|
[clang-format] Support lightweight Objective-C generics
Summary:
Previously, `clang-format` didn't understand lightweight
Objective-C generics, which have the form:
```
@interface Foo <KeyType,
ValueTypeWithConstraint : Foo,
AnotherValueTypeWithGenericConstraint: Bar<Baz>, ... > ...
```
The lightweight generic specifier list appears before the base
class, if present, but because it starts with < like the protocol
specifier list, `UnwrappedLineParser` was getting confused and
failed to parse interfaces with both generics and protocol lists:
```
@interface Foo <KeyType> : NSObject <NSCopying>
```
Since the parsed line would be incomplete, the format result
would be very confused (e.g., https://bugs.llvm.org/show_bug.cgi?id=24381).
This fixes the issue by explicitly parsing the ObjC lightweight
generic conformance list, so the line is fully parsed.
Fixes: https://bugs.llvm.org/show_bug.cgi?id=24381
Test Plan: New tests added. Ran tests with:
% make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests
Reviewers: djasper, jolesiak
Reviewed By: djasper
Subscribers: klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D45185
llvm-svn: 329298
2018-04-05 23:26:25 +08:00
|
|
|
// @interface can be followed by a lightweight generic
|
|
|
|
// specialization list, then either a base class or a category.
|
|
|
|
if (FormatTok->Tok.is(tok::less)) {
|
|
|
|
// Unlike protocol lists, generic parameterizations support
|
|
|
|
// nested angles:
|
|
|
|
//
|
|
|
|
// @interface Foo<ValueType : id <NSCopying, NSSecureCoding>> :
|
|
|
|
// NSObject <NSCopying, NSSecureCoding>
|
|
|
|
//
|
|
|
|
// so we need to count how many open angles we have left.
|
|
|
|
unsigned NumOpenAngles = 1;
|
|
|
|
do {
|
|
|
|
nextToken();
|
|
|
|
// Early exit in case someone forgot a close angle.
|
|
|
|
if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
|
|
|
|
FormatTok->Tok.isObjCAtKeyword(tok::objc_end))
|
|
|
|
break;
|
|
|
|
if (FormatTok->Tok.is(tok::less))
|
|
|
|
++NumOpenAngles;
|
|
|
|
else if (FormatTok->Tok.is(tok::greater)) {
|
|
|
|
assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative");
|
|
|
|
--NumOpenAngles;
|
|
|
|
}
|
|
|
|
} while (!eof() && NumOpenAngles != 0);
|
|
|
|
nextToken(); // Skip '>'.
|
|
|
|
}
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::colon)) {
|
2013-01-10 04:25:35 +08:00
|
|
|
nextToken();
|
2013-03-20 20:37:50 +08:00
|
|
|
nextToken(); // base class name
|
2013-05-28 19:55:06 +08:00
|
|
|
} else if (FormatTok->Tok.is(tok::l_paren))
|
2013-01-10 04:25:35 +08:00
|
|
|
// Skip category, if present.
|
|
|
|
parseParens();
|
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::less))
|
2013-01-10 05:15:03 +08:00
|
|
|
parseObjCProtocolList();
|
2013-01-10 04:25:35 +08:00
|
|
|
|
2014-05-03 01:01:46 +08:00
|
|
|
if (FormatTok->Tok.is(tok::l_brace)) {
|
2015-09-29 22:57:55 +08:00
|
|
|
if (Style.BraceWrapping.AfterObjCDeclaration)
|
2014-05-03 01:01:46 +08:00
|
|
|
addUnwrappedLine();
|
2013-06-26 08:30:14 +08:00
|
|
|
parseBlock(/*MustBeDeclaration=*/true);
|
2014-05-03 01:01:46 +08:00
|
|
|
}
|
2013-01-10 04:25:35 +08:00
|
|
|
|
|
|
|
// With instance variables, this puts '}' on its own line. Without instance
|
|
|
|
// variables, this ends the @interface line.
|
|
|
|
addUnwrappedLine();
|
|
|
|
|
2013-01-10 05:15:03 +08:00
|
|
|
parseObjCUntilAtEnd();
|
|
|
|
}
|
2013-01-10 04:25:35 +08:00
|
|
|
|
2018-01-24 01:10:25 +08:00
|
|
|
// Returns true for the declaration/definition form of @protocol,
|
|
|
|
// false for the expression form.
|
|
|
|
bool UnwrappedLineParser::parseObjCProtocol() {
|
|
|
|
assert(FormatTok->Tok.getObjCKeywordID() == tok::objc_protocol);
|
2013-01-10 05:15:03 +08:00
|
|
|
nextToken();
|
2018-01-24 01:10:25 +08:00
|
|
|
|
|
|
|
if (FormatTok->is(tok::l_paren))
|
|
|
|
// The expression form of @protocol, e.g. "Protocol* p = @protocol(foo);".
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The definition/declaration form,
|
|
|
|
// @protocol Foo
|
|
|
|
// - (int)someMethod;
|
|
|
|
// @end
|
|
|
|
|
2013-03-20 20:37:50 +08:00
|
|
|
nextToken(); // protocol name
|
2013-01-10 05:15:03 +08:00
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::less))
|
2013-01-10 05:15:03 +08:00
|
|
|
parseObjCProtocolList();
|
|
|
|
|
|
|
|
// Check for protocol declaration.
|
2013-05-28 19:55:06 +08:00
|
|
|
if (FormatTok->Tok.is(tok::semi)) {
|
2013-01-10 05:15:03 +08:00
|
|
|
nextToken();
|
2018-01-24 01:10:25 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
return true;
|
2013-01-10 05:15:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
addUnwrappedLine();
|
|
|
|
parseObjCUntilAtEnd();
|
2018-01-24 01:10:25 +08:00
|
|
|
return true;
|
2013-01-10 04:25:35 +08:00
|
|
|
}
|
|
|
|
|
2015-02-20 00:14:18 +08:00
|
|
|
void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
|
2016-04-19 22:55:37 +08:00
|
|
|
bool IsImport = FormatTok->is(Keywords.kw_import);
|
|
|
|
assert(IsImport || FormatTok->is(tok::kw_export));
|
2015-02-20 00:07:32 +08:00
|
|
|
nextToken();
|
2015-02-20 00:14:18 +08:00
|
|
|
|
2015-05-11 17:14:50 +08:00
|
|
|
// Consume the "default" in "export default class/function".
|
2015-05-11 17:03:10 +08:00
|
|
|
if (FormatTok->is(tok::kw_default))
|
|
|
|
nextToken();
|
2015-05-11 17:14:50 +08:00
|
|
|
|
2016-04-25 06:05:09 +08:00
|
|
|
// Consume "async function", "function" and "default function", so that these
|
|
|
|
// get parsed as free-standing JS functions, i.e. do not require a trailing
|
|
|
|
// semicolon.
|
|
|
|
if (FormatTok->is(Keywords.kw_async))
|
|
|
|
nextToken();
|
2015-05-11 17:03:10 +08:00
|
|
|
if (FormatTok->is(Keywords.kw_function)) {
|
|
|
|
nextToken();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-19 22:55:37 +08:00
|
|
|
// For imports, `export *`, `export {...}`, consume the rest of the line up
|
|
|
|
// to the terminating `;`. For everything else, just return and continue
|
|
|
|
// parsing the structural element, i.e. the declaration or expression for
|
|
|
|
// `export default`.
|
|
|
|
if (!IsImport && !FormatTok->isOneOf(tok::l_brace, tok::star) &&
|
|
|
|
!FormatTok->isStringLiteral())
|
|
|
|
return;
|
2015-02-20 00:14:18 +08:00
|
|
|
|
2017-01-09 16:56:36 +08:00
|
|
|
while (!eof()) {
|
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
return;
|
2017-11-09 21:22:03 +08:00
|
|
|
if (Line->Tokens.empty()) {
|
2017-01-09 16:56:36 +08:00
|
|
|
// Common issue: Automatic Semicolon Insertion wrapped the line, so the
|
|
|
|
// import statement should terminate.
|
|
|
|
return;
|
|
|
|
}
|
2016-01-07 16:53:35 +08:00
|
|
|
if (FormatTok->is(tok::l_brace)) {
|
|
|
|
FormatTok->BlockKind = BK_Block;
|
2017-07-03 23:05:14 +08:00
|
|
|
nextToken();
|
2016-01-07 16:53:35 +08:00
|
|
|
parseBracedList();
|
|
|
|
} else {
|
|
|
|
nextToken();
|
|
|
|
}
|
2015-02-20 00:07:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-01 17:09:54 +08:00
|
|
|
void UnwrappedLineParser::parseStatementMacro() {
|
clang-format: better handle statement macros
Summary:
Some macros are used in the body of function, and actually contain the trailing semicolon: they should thus be automatically followed by a new line, and not get merged with the next line. This is for example the case with Qt's Q_UNUSED macro:
void foo(int a, int b) {
Q_UNUSED(a)
return b;
}
This patch deals with these cases by introducing a new option to specify list of statement macros. This re-uses the system already in place for foreach macros, to ensure there is no impact on performance.
Reviewers: krasimir, djasper, klimek
Reviewed By: krasimir
Subscribers: acoomans, mgrang, alexfh, klimek, cfe-commits
Differential Revision: https://reviews.llvm.org/D33440
llvm-svn: 343602
2018-10-03 00:37:51 +08:00
|
|
|
nextToken();
|
|
|
|
if (FormatTok->is(tok::l_paren))
|
|
|
|
parseParens();
|
|
|
|
if (FormatTok->is(tok::semi))
|
|
|
|
nextToken();
|
|
|
|
addUnwrappedLine();
|
|
|
|
}
|
|
|
|
|
2013-09-06 00:05:56 +08:00
|
|
|
LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
|
|
|
|
StringRef Prefix = "") {
|
2017-10-30 22:01:50 +08:00
|
|
|
llvm::dbgs() << Prefix << "Line(" << Line.Level
|
|
|
|
<< ", FSC=" << Line.FirstStartColumn << ")"
|
2013-09-05 17:29:45 +08:00
|
|
|
<< (Line.InPPDirective ? " MACRO" : "") << ": ";
|
|
|
|
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
|
|
|
|
E = Line.Tokens.end();
|
|
|
|
I != E; ++I) {
|
2017-01-25 21:58:58 +08:00
|
|
|
llvm::dbgs() << I->Tok->Tok.getName() << "["
|
2017-09-20 17:51:03 +08:00
|
|
|
<< "T=" << I->Tok->Type << ", OC=" << I->Tok->OriginalColumn
|
|
|
|
<< "] ";
|
2013-09-05 17:29:45 +08:00
|
|
|
}
|
|
|
|
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
|
|
|
|
E = Line.Tokens.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
const UnwrappedLineNode &Node = *I;
|
|
|
|
for (SmallVectorImpl<UnwrappedLine>::const_iterator
|
|
|
|
I = Node.Children.begin(),
|
|
|
|
E = Node.Children.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
printDebugInfo(*I, "\nChild: ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm::dbgs() << "\n";
|
|
|
|
}
|
|
|
|
|
2012-12-04 02:12:45 +08:00
|
|
|
void UnwrappedLineParser::addUnwrappedLine() {
|
2013-01-16 17:10:19 +08:00
|
|
|
if (Line->Tokens.empty())
|
2013-01-08 22:56:18 +08:00
|
|
|
return;
|
2018-05-15 21:30:56 +08:00
|
|
|
LLVM_DEBUG({
|
2013-09-05 17:29:45 +08:00
|
|
|
if (CurrentLines == &Lines)
|
|
|
|
printDebugInfo(*Line);
|
2013-01-16 20:31:12 +08:00
|
|
|
});
|
2015-05-31 19:18:05 +08:00
|
|
|
CurrentLines->push_back(std::move(*Line));
|
2013-01-16 17:10:19 +08:00
|
|
|
Line->Tokens.clear();
|
2017-03-02 00:38:08 +08:00
|
|
|
Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
|
2017-10-30 22:01:50 +08:00
|
|
|
Line->FirstStartColumn = 0;
|
2013-01-18 22:04:34 +08:00
|
|
|
if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
|
2015-05-31 19:18:05 +08:00
|
|
|
CurrentLines->append(
|
|
|
|
std::make_move_iterator(PreprocessorDirectives.begin()),
|
|
|
|
std::make_move_iterator(PreprocessorDirectives.end()));
|
2013-01-18 22:04:34 +08:00
|
|
|
PreprocessorDirectives.clear();
|
|
|
|
}
|
2017-09-20 17:29:37 +08:00
|
|
|
// Disconnect the current token from the last token on the previous line.
|
|
|
|
FormatTok->Previous = nullptr;
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
|
2012-12-04 02:12:45 +08:00
|
|
|
|
2014-05-09 21:11:16 +08:00
|
|
|
bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
|
2014-04-11 20:27:47 +08:00
|
|
|
return (Line->InPPDirective || FormatTok.HasUnescapedNewline) &&
|
|
|
|
FormatTok.NewlinesBefore > 0;
|
|
|
|
}
|
|
|
|
|
2017-01-25 21:58:58 +08:00
|
|
|
// Checks if \p FormatTok is a line comment that continues the line comment
|
|
|
|
// section on \p Line.
|
2019-11-19 19:18:51 +08:00
|
|
|
static bool
|
|
|
|
continuesLineCommentSection(const FormatToken &FormatTok,
|
|
|
|
const UnwrappedLine &Line,
|
|
|
|
const llvm::Regex &CommentPragmasRegex) {
|
2017-01-25 21:58:58 +08:00
|
|
|
if (Line.Tokens.empty())
|
|
|
|
return false;
|
2017-01-31 03:18:55 +08:00
|
|
|
|
2017-02-02 23:32:19 +08:00
|
|
|
StringRef IndentContent = FormatTok.TokenText;
|
|
|
|
if (FormatTok.TokenText.startswith("//") ||
|
|
|
|
FormatTok.TokenText.startswith("/*"))
|
|
|
|
IndentContent = FormatTok.TokenText.substr(2);
|
|
|
|
if (CommentPragmasRegex.match(IndentContent))
|
|
|
|
return false;
|
|
|
|
|
2017-01-25 21:58:58 +08:00
|
|
|
// If Line starts with a line comment, then FormatTok continues the comment
|
2017-01-31 03:18:55 +08:00
|
|
|
// section if its original column is greater or equal to the original start
|
2017-01-25 21:58:58 +08:00
|
|
|
// column of the line.
|
|
|
|
//
|
2017-01-31 03:18:55 +08:00
|
|
|
// Define the min column token of a line as follows: if a line ends in '{' or
|
|
|
|
// contains a '{' followed by a line comment, then the min column token is
|
|
|
|
// that '{'. Otherwise, the min column token of the line is the first token of
|
|
|
|
// the line.
|
|
|
|
//
|
|
|
|
// If Line starts with a token other than a line comment, then FormatTok
|
|
|
|
// continues the comment section if its original column is greater than the
|
|
|
|
// original start column of the min column token of the line.
|
2017-01-25 21:58:58 +08:00
|
|
|
//
|
|
|
|
// For example, the second line comment continues the first in these cases:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// // first line
|
|
|
|
// // second line
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// and:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// // first line
|
|
|
|
// // second line
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// and:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// int i; // first line
|
|
|
|
// // second line
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-31 03:18:55 +08:00
|
|
|
// and:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-31 03:18:55 +08:00
|
|
|
// do { // first line
|
|
|
|
// // second line
|
|
|
|
// int i;
|
|
|
|
// } while (true);
|
2017-01-25 21:58:58 +08:00
|
|
|
//
|
2017-02-02 22:36:50 +08:00
|
|
|
// and:
|
|
|
|
//
|
|
|
|
// enum {
|
|
|
|
// a, // first line
|
|
|
|
// // second line
|
|
|
|
// b
|
|
|
|
// };
|
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// The second line comment doesn't continue the first in these cases:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// // first line
|
|
|
|
// // second line
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// and:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-25 21:58:58 +08:00
|
|
|
// int i; // first line
|
|
|
|
// // second line
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-31 03:18:55 +08:00
|
|
|
// and:
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
2017-01-31 03:18:55 +08:00
|
|
|
// do { // first line
|
|
|
|
// // second line
|
|
|
|
// int i;
|
|
|
|
// } while (true);
|
2017-02-02 22:36:50 +08:00
|
|
|
//
|
|
|
|
// and:
|
|
|
|
//
|
|
|
|
// enum {
|
|
|
|
// a, // first line
|
|
|
|
// // second line
|
|
|
|
// };
|
2017-01-31 03:18:55 +08:00
|
|
|
const FormatToken *MinColumnToken = Line.Tokens.front().Tok;
|
|
|
|
|
|
|
|
// Scan for '{//'. If found, use the column of '{' as a min column for line
|
|
|
|
// comment section continuation.
|
|
|
|
const FormatToken *PreviousToken = nullptr;
|
2017-03-10 21:09:29 +08:00
|
|
|
for (const UnwrappedLineNode &Node : Line.Tokens) {
|
2017-01-31 03:18:55 +08:00
|
|
|
if (PreviousToken && PreviousToken->is(tok::l_brace) &&
|
|
|
|
isLineComment(*Node.Tok)) {
|
|
|
|
MinColumnToken = PreviousToken;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PreviousToken = Node.Tok;
|
2017-02-02 22:36:50 +08:00
|
|
|
|
|
|
|
// Grab the last newline preceding a token in this unwrapped line.
|
|
|
|
if (Node.Tok->NewlinesBefore > 0) {
|
|
|
|
MinColumnToken = Node.Tok;
|
|
|
|
}
|
2017-01-31 03:18:55 +08:00
|
|
|
}
|
|
|
|
if (PreviousToken && PreviousToken->is(tok::l_brace)) {
|
|
|
|
MinColumnToken = PreviousToken;
|
|
|
|
}
|
|
|
|
|
2017-05-22 18:07:56 +08:00
|
|
|
return continuesLineComment(FormatTok, /*Previous=*/Line.Tokens.back().Tok,
|
|
|
|
MinColumnToken);
|
2017-01-25 21:58:58 +08:00
|
|
|
}
|
|
|
|
|
2013-01-23 00:31:55 +08:00
|
|
|
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
|
|
|
|
bool JustComments = Line->Tokens.empty();
|
2013-05-28 19:55:06 +08:00
|
|
|
for (SmallVectorImpl<FormatToken *>::const_iterator
|
2013-01-23 00:31:55 +08:00
|
|
|
I = CommentsBeforeNextToken.begin(),
|
|
|
|
E = CommentsBeforeNextToken.end();
|
|
|
|
I != E; ++I) {
|
2017-01-25 21:58:58 +08:00
|
|
|
// Line comments that belong to the same line comment section are put on the
|
|
|
|
// same line since later we might want to reflow content between them.
|
2017-01-31 21:32:38 +08:00
|
|
|
// Additional fine-grained breaking of line comment sections is controlled
|
|
|
|
// by the class BreakableLineCommentSection in case it is desirable to keep
|
|
|
|
// several line comment sections in the same unwrapped line.
|
|
|
|
//
|
|
|
|
// FIXME: Consider putting separate line comment sections as children to the
|
|
|
|
// unwrapped line instead.
|
2017-02-02 23:32:19 +08:00
|
|
|
(*I)->ContinuesLineCommentSection =
|
2017-05-22 18:07:56 +08:00
|
|
|
continuesLineCommentSection(**I, *Line, CommentPragmasRegex);
|
2017-02-02 22:36:50 +08:00
|
|
|
if (isOnNewLine(**I) && JustComments && !(*I)->ContinuesLineCommentSection)
|
2013-01-23 00:31:55 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
pushToken(*I);
|
|
|
|
}
|
2015-05-13 19:35:53 +08:00
|
|
|
if (NewlineBeforeNext && JustComments)
|
2013-01-23 00:31:55 +08:00
|
|
|
addUnwrappedLine();
|
|
|
|
CommentsBeforeNextToken.clear();
|
|
|
|
}
|
|
|
|
|
2017-07-24 22:51:59 +08:00
|
|
|
void UnwrappedLineParser::nextToken(int LevelDifference) {
|
2012-12-04 02:12:45 +08:00
|
|
|
if (eof())
|
|
|
|
return;
|
2014-04-11 20:27:47 +08:00
|
|
|
flushComments(isOnNewLine(*FormatTok));
|
2013-01-23 00:31:55 +08:00
|
|
|
pushToken(FormatTok);
|
2017-09-20 17:51:03 +08:00
|
|
|
FormatToken *Previous = FormatTok;
|
2016-03-15 03:21:36 +08:00
|
|
|
if (Style.Language != FormatStyle::LK_JavaScript)
|
2017-07-24 22:51:59 +08:00
|
|
|
readToken(LevelDifference);
|
2016-03-15 03:21:36 +08:00
|
|
|
else
|
|
|
|
readTokenWithJavaScriptASI();
|
2017-09-20 17:29:37 +08:00
|
|
|
FormatTok->Previous = Previous;
|
2016-01-09 23:56:28 +08:00
|
|
|
}
|
|
|
|
|
2017-02-08 18:30:44 +08:00
|
|
|
void UnwrappedLineParser::distributeComments(
|
|
|
|
const SmallVectorImpl<FormatToken *> &Comments,
|
|
|
|
const FormatToken *NextTok) {
|
|
|
|
// Whether or not a line comment token continues a line is controlled by
|
2017-05-22 18:07:56 +08:00
|
|
|
// the method continuesLineCommentSection, with the following caveat:
|
2017-02-08 18:30:44 +08:00
|
|
|
//
|
|
|
|
// Define a trail of Comments to be a nonempty proper postfix of Comments such
|
|
|
|
// that each comment line from the trail is aligned with the next token, if
|
|
|
|
// the next token exists. If a trail exists, the beginning of the maximal
|
|
|
|
// trail is marked as a start of a new comment section.
|
|
|
|
//
|
|
|
|
// For example in this code:
|
|
|
|
//
|
|
|
|
// int a; // line about a
|
|
|
|
// // line 1 about b
|
|
|
|
// // line 2 about b
|
|
|
|
// int b;
|
|
|
|
//
|
|
|
|
// the two lines about b form a maximal trail, so there are two sections, the
|
|
|
|
// first one consisting of the single comment "// line about a" and the
|
|
|
|
// second one consisting of the next two comments.
|
|
|
|
if (Comments.empty())
|
|
|
|
return;
|
|
|
|
bool ShouldPushCommentsInCurrentLine = true;
|
|
|
|
bool HasTrailAlignedWithNextToken = false;
|
|
|
|
unsigned StartOfTrailAlignedWithNextToken = 0;
|
|
|
|
if (NextTok) {
|
|
|
|
// We are skipping the first element intentionally.
|
|
|
|
for (unsigned i = Comments.size() - 1; i > 0; --i) {
|
|
|
|
if (Comments[i]->OriginalColumn == NextTok->OriginalColumn) {
|
|
|
|
HasTrailAlignedWithNextToken = true;
|
|
|
|
StartOfTrailAlignedWithNextToken = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (unsigned i = 0, e = Comments.size(); i < e; ++i) {
|
|
|
|
FormatToken *FormatTok = Comments[i];
|
2017-09-20 17:51:03 +08:00
|
|
|
if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
|
2017-02-08 18:30:44 +08:00
|
|
|
FormatTok->ContinuesLineCommentSection = false;
|
|
|
|
} else {
|
|
|
|
FormatTok->ContinuesLineCommentSection =
|
2017-05-22 18:07:56 +08:00
|
|
|
continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
|
2017-02-08 18:30:44 +08:00
|
|
|
}
|
|
|
|
if (!FormatTok->ContinuesLineCommentSection &&
|
|
|
|
(isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {
|
|
|
|
ShouldPushCommentsInCurrentLine = false;
|
|
|
|
}
|
|
|
|
if (ShouldPushCommentsInCurrentLine) {
|
|
|
|
pushToken(FormatTok);
|
|
|
|
} else {
|
|
|
|
CommentsBeforeNextToken.push_back(FormatTok);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-24 22:51:59 +08:00
|
|
|
void UnwrappedLineParser::readToken(int LevelDifference) {
|
2017-02-08 18:30:44 +08:00
|
|
|
SmallVector<FormatToken *, 1> Comments;
|
2013-01-23 00:31:55 +08:00
|
|
|
do {
|
|
|
|
FormatTok = Tokens->getNextToken();
|
2014-03-13 21:59:48 +08:00
|
|
|
assert(FormatTok);
|
2013-05-28 19:55:06 +08:00
|
|
|
while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) &&
|
|
|
|
(FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {
|
2017-02-08 18:30:44 +08:00
|
|
|
distributeComments(Comments, FormatTok);
|
|
|
|
Comments.clear();
|
2013-01-23 00:31:55 +08:00
|
|
|
// If there is an unfinished unwrapped line, we flush the preprocessor
|
|
|
|
// directives only after that unwrapped line was finished later.
|
2015-02-08 17:34:49 +08:00
|
|
|
bool SwitchToPreprocessorLines = !Line->Tokens.empty();
|
2013-01-23 00:31:55 +08:00
|
|
|
ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
|
2017-07-24 22:51:59 +08:00
|
|
|
assert((LevelDifference >= 0 ||
|
|
|
|
static_cast<unsigned>(-LevelDifference) <= Line->Level) &&
|
|
|
|
"LevelDifference makes Line->Level negative");
|
|
|
|
Line->Level += LevelDifference;
|
2013-04-03 20:38:53 +08:00
|
|
|
// Comments stored before the preprocessor directive need to be output
|
|
|
|
// before the preprocessor directive, at the same level as the
|
|
|
|
// preprocessor directive, as we consider them to apply to the directive.
|
[clang-format] BeforeHash added to IndentPPDirectives
Summary:
The option BeforeHash added to IndentPPDirectives.
Fixes Bug 36019. https://bugs.llvm.org/show_bug.cgi?id=36019
Reviewers: djasper, klimek, krasimir, sammccall, mprobst, Nicola, MyDeveloperDay
Reviewed By: klimek, MyDeveloperDay
Subscribers: kadircet, MyDeveloperDay, mnussbaum, geleji, ufna, cfe-commits
Patch by to-mix.
Differential Revision: https://reviews.llvm.org/D52150
llvm-svn: 356613
2019-03-21 04:49:43 +08:00
|
|
|
if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
|
|
|
|
PPBranchLevel > 0)
|
|
|
|
Line->Level += PPBranchLevel;
|
2014-04-11 20:27:47 +08:00
|
|
|
flushComments(isOnNewLine(*FormatTok));
|
2013-01-23 00:31:55 +08:00
|
|
|
parsePPDirective();
|
|
|
|
}
|
2014-04-14 17:14:11 +08:00
|
|
|
while (FormatTok->Type == TT_ConflictStart ||
|
|
|
|
FormatTok->Type == TT_ConflictEnd ||
|
|
|
|
FormatTok->Type == TT_ConflictAlternative) {
|
|
|
|
if (FormatTok->Type == TT_ConflictStart) {
|
|
|
|
conditionalCompilationStart(/*Unreachable=*/false);
|
|
|
|
} else if (FormatTok->Type == TT_ConflictAlternative) {
|
|
|
|
conditionalCompilationAlternative();
|
2014-05-09 21:11:16 +08:00
|
|
|
} else if (FormatTok->Type == TT_ConflictEnd) {
|
2014-04-14 17:14:11 +08:00
|
|
|
conditionalCompilationEnd();
|
|
|
|
}
|
|
|
|
FormatTok = Tokens->getNextToken();
|
|
|
|
FormatTok->MustBreakBefore = true;
|
|
|
|
}
|
2013-05-25 02:24:24 +08:00
|
|
|
|
2017-07-28 15:56:14 +08:00
|
|
|
if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) &&
|
2013-05-25 02:24:24 +08:00
|
|
|
!Line->InPPDirective) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-08 18:30:44 +08:00
|
|
|
if (!FormatTok->Tok.is(tok::comment)) {
|
|
|
|
distributeComments(Comments, FormatTok);
|
|
|
|
Comments.clear();
|
2013-01-23 00:31:55 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-02-08 18:30:44 +08:00
|
|
|
|
|
|
|
Comments.push_back(FormatTok);
|
2013-01-23 00:31:55 +08:00
|
|
|
} while (!eof());
|
2017-02-08 18:30:44 +08:00
|
|
|
|
|
|
|
distributeComments(Comments, nullptr);
|
|
|
|
Comments.clear();
|
2013-01-23 00:31:55 +08:00
|
|
|
}
|
|
|
|
|
2013-05-28 19:55:06 +08:00
|
|
|
void UnwrappedLineParser::pushToken(FormatToken *Tok) {
|
2013-09-05 17:29:45 +08:00
|
|
|
Line->Tokens.push_back(UnwrappedLineNode(Tok));
|
2013-01-23 00:31:55 +08:00
|
|
|
if (MustBreakBeforeNextToken) {
|
2013-09-05 17:29:45 +08:00
|
|
|
Line->Tokens.back().Tok->MustBreakBefore = true;
|
2013-01-23 00:31:55 +08:00
|
|
|
MustBreakBeforeNextToken = false;
|
2013-01-05 07:34:14 +08:00
|
|
|
}
|
2012-12-04 02:12:45 +08:00
|
|
|
}
|
|
|
|
|
2013-01-07 21:26:07 +08:00
|
|
|
} // end namespace format
|
|
|
|
} // end namespace clang
|