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:
Nico Weber 2015-02-04 15:26:27 +00:00
parent e67d27f5cc
commit fac2371be3
7 changed files with 57 additions and 12 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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 &&

View File

@ -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(

View File

@ -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;

View File

@ -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))) {

View File

@ -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"