forked from OSchip/llvm-project
clang-format: Add support for SEH __try / __except / __finally blocks.
This lets clang-format format __try { } __except(0) { } and __try { } __finally { } correctly. __try and __finally are keywords if `LangOpts.MicrosoftExt` is set, so this turns this on. This also enables a few other keywords, but it shouldn't overly perturb regular clang-format operation. __except is a context-sensitive keyword, so `AdditionalKeywords` needs to be passed around to a few more places. Fixes PR22321. llvm-svn: 228148
This commit is contained in:
parent
e67d27f5cc
commit
fac2371be3
|
@ -1123,7 +1123,8 @@ public:
|
|||
ContinuationIndenter Indenter(Style, Tokens.getKeywords(), SourceMgr,
|
||||
Whitespaces, Encoding,
|
||||
BinPackInconclusiveFunctions);
|
||||
UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
|
||||
UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style,
|
||||
Tokens.getKeywords());
|
||||
Formatter.format(AnnotatedLines, /*DryRun=*/false);
|
||||
return Whitespaces.generateReplacements();
|
||||
}
|
||||
|
@ -1399,6 +1400,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
|
|||
LangOpts.Bool = 1;
|
||||
LangOpts.ObjC1 = 1;
|
||||
LangOpts.ObjC2 = 1;
|
||||
LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
|
||||
return LangOpts;
|
||||
}
|
||||
|
||||
|
|
|
@ -555,6 +555,7 @@ struct AdditionalKeywords {
|
|||
kw_package = &IdentTable.get("package");
|
||||
kw_synchronized = &IdentTable.get("synchronized");
|
||||
kw_throws = &IdentTable.get("throws");
|
||||
kw___except = &IdentTable.get("__except");
|
||||
|
||||
kw_option = &IdentTable.get("option");
|
||||
kw_optional = &IdentTable.get("optional");
|
||||
|
@ -563,12 +564,13 @@ struct AdditionalKeywords {
|
|||
kw_returns = &IdentTable.get("returns");
|
||||
}
|
||||
|
||||
// ObjC context sensitive keywords.
|
||||
// Context sensitive keywords.
|
||||
IdentifierInfo *kw_in;
|
||||
IdentifierInfo *kw_CF_ENUM;
|
||||
IdentifierInfo *kw_CF_OPTIONS;
|
||||
IdentifierInfo *kw_NS_ENUM;
|
||||
IdentifierInfo *kw_NS_OPTIONS;
|
||||
IdentifierInfo *kw___except;
|
||||
|
||||
// JavaScript keywords.
|
||||
IdentifierInfo *kw_finally;
|
||||
|
|
|
@ -1701,8 +1701,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
|||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
|
||||
(Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
|
||||
tok::kw_switch, tok::kw_case) ||
|
||||
(Left.isOneOf(tok::kw_try, tok::kw_catch, tok::kw_new,
|
||||
tok::kw_delete) &&
|
||||
(Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
|
||||
tok::kw_new, tok::kw_delete) &&
|
||||
(!Left.Previous || Left.Previous->isNot(tok::period))) ||
|
||||
Left.IsForEachMacro)) ||
|
||||
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
|
||||
|
|
|
@ -27,7 +27,8 @@ bool startsExternCBlock(const AnnotatedLine &Line) {
|
|||
|
||||
class LineJoiner {
|
||||
public:
|
||||
LineJoiner(const FormatStyle &Style) : Style(Style) {}
|
||||
LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords)
|
||||
: Style(Style), Keywords(Keywords) {}
|
||||
|
||||
/// \brief Calculates how many lines can be merged into 1 starting at \p I.
|
||||
unsigned
|
||||
|
@ -200,7 +201,9 @@ private:
|
|||
if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
|
||||
return 0;
|
||||
if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
|
||||
tok::kw_catch, tok::kw_for, tok::r_brace)) {
|
||||
tok::kw___try, tok::kw_catch, tok::kw___finally,
|
||||
tok::kw_for, tok::r_brace) ||
|
||||
Line.First->is(Keywords.kw___except)) {
|
||||
if (!Style.AllowShortBlocksOnASingleLine)
|
||||
return 0;
|
||||
if (!Style.AllowShortIfStatementsOnASingleLine &&
|
||||
|
@ -211,7 +214,11 @@ private:
|
|||
return 0;
|
||||
// FIXME: Consider an option to allow short exception handling clauses on
|
||||
// a single line.
|
||||
if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
|
||||
// FIXME: This isn't covered by tests.
|
||||
// FIXME: For catch, __except, __finally the first token on the line
|
||||
// is '}', so this isn't correct here.
|
||||
if (Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
|
||||
Keywords.kw___except, tok::kw___finally))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -286,6 +293,7 @@ private:
|
|||
}
|
||||
|
||||
const FormatStyle &Style;
|
||||
const AdditionalKeywords &Keywords;
|
||||
};
|
||||
|
||||
class NoColumnLimitFormatter {
|
||||
|
@ -324,7 +332,7 @@ unsigned
|
|||
UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
|
||||
bool DryRun, int AdditionalIndent,
|
||||
bool FixBadIndentation) {
|
||||
LineJoiner Joiner(Style);
|
||||
LineJoiner Joiner(Style, Keywords);
|
||||
|
||||
// Try to look up already computed penalty in DryRun-mode.
|
||||
std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
|
||||
|
|
|
@ -32,8 +32,10 @@ class UnwrappedLineFormatter {
|
|||
public:
|
||||
UnwrappedLineFormatter(ContinuationIndenter *Indenter,
|
||||
WhitespaceManager *Whitespaces,
|
||||
const FormatStyle &Style)
|
||||
: Indenter(Indenter), Whitespaces(Whitespaces), Style(Style) {}
|
||||
const FormatStyle &Style,
|
||||
const AdditionalKeywords &Keywords)
|
||||
: Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
|
||||
Keywords(Keywords) {}
|
||||
|
||||
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
|
||||
int AdditionalIndent = 0, bool FixBadIndentation = false);
|
||||
|
@ -153,6 +155,7 @@ private:
|
|||
ContinuationIndenter *Indenter;
|
||||
WhitespaceManager *Whitespaces;
|
||||
FormatStyle Style;
|
||||
const AdditionalKeywords &Keywords;
|
||||
|
||||
llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
|
||||
|
||||
|
|
|
@ -374,6 +374,7 @@ void UnwrappedLineParser::calculateBraceTypes() {
|
|||
case tok::kw_for:
|
||||
case tok::kw_switch:
|
||||
case tok::kw_try:
|
||||
case tok::kw___try:
|
||||
if (!LBraceStack.empty())
|
||||
LBraceStack.back()->BlockKind = BK_Block;
|
||||
break;
|
||||
|
@ -713,6 +714,7 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
parseCaseLabel();
|
||||
return;
|
||||
case tok::kw_try:
|
||||
case tok::kw___try:
|
||||
parseTryCatch();
|
||||
return;
|
||||
case tok::kw_extern:
|
||||
|
@ -1149,7 +1151,7 @@ void UnwrappedLineParser::parseIfThenElse() {
|
|||
}
|
||||
|
||||
void UnwrappedLineParser::parseTryCatch() {
|
||||
assert(FormatTok->is(tok::kw_try) && "'try' expected");
|
||||
assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected");
|
||||
nextToken();
|
||||
bool NeedsUnwrappedLine = false;
|
||||
if (FormatTok->is(tok::colon)) {
|
||||
|
@ -1189,7 +1191,8 @@ void UnwrappedLineParser::parseTryCatch() {
|
|||
parseStructuralElement();
|
||||
--Line->Level;
|
||||
}
|
||||
while (FormatTok->is(tok::kw_catch) ||
|
||||
while (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))) {
|
||||
|
|
|
@ -2244,6 +2244,26 @@ TEST_F(FormatTest, FormatTryCatch) {
|
|||
verifyFormat("try {} catch (");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, FormatSEHTryCatch) {
|
||||
verifyFormat("__try {\n"
|
||||
" int a = b * c;\n"
|
||||
"} __except (EXCEPTION_EXECUTE_HANDLER) {\n"
|
||||
" // Do nothing.\n"
|
||||
"}");
|
||||
|
||||
verifyFormat("__try {\n"
|
||||
" int a = b * c;\n"
|
||||
"} __finally {\n"
|
||||
" // Do nothing.\n"
|
||||
"}");
|
||||
|
||||
verifyFormat("DEBUG({\n"
|
||||
" __try {\n"
|
||||
" } __finally {\n"
|
||||
" }\n"
|
||||
"});\n");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, IncompleteTryCatchBlocks) {
|
||||
verifyFormat("try {\n"
|
||||
" f();\n"
|
||||
|
@ -2276,6 +2296,13 @@ TEST_F(FormatTest, FormatTryCatchBraceStyles) {
|
|||
" // something\n"
|
||||
"}",
|
||||
Style);
|
||||
verifyFormat("__try {\n"
|
||||
" // something\n"
|
||||
"}\n"
|
||||
"__finally {\n"
|
||||
" // something\n"
|
||||
"}",
|
||||
Style);
|
||||
Style.BreakBeforeBraces = FormatStyle::BS_Allman;
|
||||
verifyFormat("try\n"
|
||||
"{\n"
|
||||
|
|
Loading…
Reference in New Issue