Error recovery part 2

Summary: Adds recovery for structural errors in clang-format.

Reviewers: djasper

Reviewed By: djasper

CC: cfe-commits, silvas

Differential Revision: http://llvm-reviews.chandlerc.com/D164

llvm-svn: 169286
This commit is contained in:
Alexander Kornienko 2012-12-04 17:27:50 +00:00
parent 4cf177e238
commit 870f9eb9cc
4 changed files with 70 additions and 32 deletions

View File

@ -72,28 +72,29 @@ public:
UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr, UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
const UnwrappedLine &Line, const UnwrappedLine &Line,
const std::vector<TokenAnnotation> &Annotations, const std::vector<TokenAnnotation> &Annotations,
tooling::Replacements &Replaces) tooling::Replacements &Replaces, bool StructuralError)
: Style(Style), : Style(Style),
SourceMgr(SourceMgr), SourceMgr(SourceMgr),
Line(Line), Line(Line),
Annotations(Annotations), Annotations(Annotations),
Replaces(Replaces) { Replaces(Replaces),
StructuralError(StructuralError) {
Parameters.PenaltyExtraLine = 100; Parameters.PenaltyExtraLine = 100;
Parameters.PenaltyIndentLevel = 5; Parameters.PenaltyIndentLevel = 5;
} }
void format() { void format() {
formatFirstToken(); unsigned Indent = formatFirstToken();
count = 0; count = 0;
IndentState State; IndentState State;
State.Column = Line.Level * 2 + Line.Tokens[0].Tok.getLength(); State.Column = Indent + Line.Tokens[0].Tok.getLength();
State.CtorInitializerOnNewLine = false; State.CtorInitializerOnNewLine = false;
State.InCtorInitializer = false; State.InCtorInitializer = false;
State.ConsumedTokens = 1; State.ConsumedTokens = 1;
//State.UsedIndent.push_back(Line.Level * 2); //State.UsedIndent.push_back(Line.Level * 2);
State.Indent.push_back(Line.Level * 2 + 4); State.Indent.push_back(Indent + 4);
State.LastSpace.push_back(Line.Level * 2); State.LastSpace.push_back(Indent);
// Start iterating at 1 as we have correctly formatted of Token #0 above. // Start iterating at 1 as we have correctly formatted of Token #0 above.
for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) { for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
@ -315,20 +316,22 @@ private:
/// \brief Add a new line and the required indent before the first Token /// \brief Add a new line and the required indent before the first Token
/// of the \c UnwrappedLine. /// of the \c UnwrappedLine.
void formatFirstToken() { unsigned formatFirstToken() {
const FormatToken &Token = Line.Tokens[0]; const FormatToken &Token = Line.Tokens[0];
if (Token.WhiteSpaceStart.isValid()) { if (!Token.WhiteSpaceStart.isValid() || StructuralError)
unsigned Newlines = return SourceMgr.getSpellingColumnNumber(Token.Tok.getLocation()) - 1;
std::min(Token.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
unsigned Offset = SourceMgr.getFileOffset(Token.WhiteSpaceStart); unsigned Newlines =
if (Newlines == 0 && Offset != 0) std::min(Token.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
Newlines = 1; unsigned Offset = SourceMgr.getFileOffset(Token.WhiteSpaceStart);
unsigned Indent = Line.Level * 2; if (Newlines == 0 && Offset != 0)
if (Token.Tok.is(tok::kw_public) || Token.Tok.is(tok::kw_protected) || Newlines = 1;
Token.Tok.is(tok::kw_private)) unsigned Indent = Line.Level * 2;
Indent += Style.AccessModifierOffset; if (Token.Tok.is(tok::kw_public) || Token.Tok.is(tok::kw_protected) ||
replaceWhitespace(Token, Newlines, Indent); Token.Tok.is(tok::kw_private))
} Indent += Style.AccessModifierOffset;
replaceWhitespace(Token, Newlines, Indent);
return Indent;
} }
FormatStyle Style; FormatStyle Style;
@ -337,6 +340,7 @@ private:
const std::vector<TokenAnnotation> &Annotations; const std::vector<TokenAnnotation> &Annotations;
tooling::Replacements &Replaces; tooling::Replacements &Replaces;
unsigned int count; unsigned int count;
bool StructuralError;
OptimizationParameters Parameters; OptimizationParameters Parameters;
}; };
@ -678,17 +682,26 @@ public:
: Style(Style), : Style(Style),
Lex(Lex), Lex(Lex),
SourceMgr(SourceMgr), SourceMgr(SourceMgr),
Ranges(Ranges) { Ranges(Ranges),
StructuralError(false) {
} }
tooling::Replacements format() { tooling::Replacements format() {
UnwrappedLineParser Parser(Lex, SourceMgr, *this); UnwrappedLineParser Parser(Lex, SourceMgr, *this);
Parser.parse(); StructuralError = Parser.parse();
for (std::vector<UnwrappedLine>::iterator I = UnwrappedLines.begin(),
E = UnwrappedLines.end();
I != E; ++I)
doFormatUnwrappedLine(*I);
return Replaces; return Replaces;
} }
private: private:
virtual void formatUnwrappedLine(const UnwrappedLine &TheLine) { virtual void formatUnwrappedLine(const UnwrappedLine &TheLine) {
UnwrappedLines.push_back(TheLine);
}
void doFormatUnwrappedLine(const UnwrappedLine &TheLine) {
if (TheLine.Tokens.size() == 0) if (TheLine.Tokens.size() == 0)
return; return;
@ -706,7 +719,8 @@ private:
TokenAnnotator Annotator(TheLine, Style, SourceMgr); TokenAnnotator Annotator(TheLine, Style, SourceMgr);
Annotator.annotate(); Annotator.annotate();
UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine,
Annotator.getAnnotations(), Replaces); Annotator.getAnnotations(), Replaces,
StructuralError);
Formatter.format(); Formatter.format();
return; return;
} }
@ -717,6 +731,8 @@ private:
SourceManager &SourceMgr; SourceManager &SourceMgr;
tooling::Replacements Replaces; tooling::Replacements Replaces;
std::vector<CharSourceRange> Ranges; std::vector<CharSourceRange> Ranges;
std::vector<UnwrappedLine> UnwrappedLines;
bool StructuralError;
}; };
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex, tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,

View File

@ -32,12 +32,13 @@ UnwrappedLineParser::UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr,
Lex.SetKeepWhitespaceMode(true); Lex.SetKeepWhitespaceMode(true);
} }
void UnwrappedLineParser::parse() { bool UnwrappedLineParser::parse() {
parseToken(); parseToken();
parseLevel(); return parseLevel();
} }
void UnwrappedLineParser::parseLevel() { bool UnwrappedLineParser::parseLevel() {
bool Error = false;
do { do {
switch (FormatTok.Tok.getKind()) { switch (FormatTok.Tok.getKind()) {
case tok::hash: case tok::hash:
@ -47,19 +48,20 @@ void UnwrappedLineParser::parseLevel() {
parseComment(); parseComment();
break; break;
case tok::l_brace: case tok::l_brace:
parseBlock(); Error |= parseBlock();
addUnwrappedLine(); addUnwrappedLine();
break; break;
case tok::r_brace: case tok::r_brace:
return; return false;
default: default:
parseStatement(); parseStatement();
break; break;
} }
} while (!eof()); } while (!eof());
return Error;
} }
void UnwrappedLineParser::parseBlock() { bool UnwrappedLineParser::parseBlock() {
nextToken(); nextToken();
// FIXME: Remove this hack to handle namespaces. // FIXME: Remove this hack to handle namespaces.
@ -74,11 +76,12 @@ void UnwrappedLineParser::parseBlock() {
--Line.Level; --Line.Level;
// FIXME: Add error handling. // FIXME: Add error handling.
if (!FormatTok.Tok.is(tok::r_brace)) if (!FormatTok.Tok.is(tok::r_brace))
return; return true;
nextToken(); nextToken();
if (FormatTok.Tok.is(tok::semi)) if (FormatTok.Tok.is(tok::semi))
nextToken(); nextToken();
return false;
} }
void UnwrappedLineParser::parsePPDirective() { void UnwrappedLineParser::parsePPDirective() {

View File

@ -79,11 +79,12 @@ public:
UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr, UnwrappedLineParser(Lexer &Lex, SourceManager &SourceMgr,
UnwrappedLineConsumer &Callback); UnwrappedLineConsumer &Callback);
void parse(); /// Returns true in case of a structural error.
bool parse();
private: private:
void parseLevel(); bool parseLevel();
void parseBlock(); bool parseBlock();
void parsePPDirective(); void parsePPDirective();
void parseComment(); void parseComment();
void parseStatement(); void parseStatement();

View File

@ -381,5 +381,23 @@ TEST_F(FormatTest, IncorrectCodeDoNoWhile) {
"};"); "};");
} }
TEST_F(FormatTest, IncorrectCodeErrorDetection) {
EXPECT_EQ("{\n{\n}\n", format("{\n{\n}\n"));
EXPECT_EQ("{\n {\n}\n", format("{\n {\n}\n"));
EXPECT_EQ("{\n {\n }\n", format("{\n {\n }\n"));
FormatStyle Style = getLLVMStyle();
Style.ColumnLimit = 10;
EXPECT_EQ("{\n"
" {\n"
" breakme(\n"
" qwe);\n"
"}\n", format("{\n"
" {\n"
" breakme(qwe);\n"
"}\n", Style));
}
} // end namespace tooling } // end namespace tooling
} // end namespace clang } // end namespace clang