clang-format: [JS] Support Closure's module statements.
These are like import statements and should not be line-wrapped. Minor restructuring of the handling of other import statements. llvm-svn: 222637
This commit is contained in:
parent
6de72e5b0c
commit
616de864da
|
@ -986,8 +986,9 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
|
|||
if (Current.Type != TT_BlockComment && Current.IsMultiline)
|
||||
return addMultilineToken(Current, State);
|
||||
|
||||
// Don't break implicit string literals.
|
||||
if (Current.Type == TT_ImplicitStringLiteral)
|
||||
// Don't break implicit string literals or import statements.
|
||||
if (Current.Type == TT_ImplicitStringLiteral ||
|
||||
State.Line->Type == LT_ImportStatement)
|
||||
return 0;
|
||||
|
||||
if (!Current.isStringLiteral() && !Current.is(tok::comment))
|
||||
|
|
|
@ -951,7 +951,8 @@ public:
|
|||
ColumnLimit = getColumnLimit(TheLine.InPPDirective);
|
||||
}
|
||||
|
||||
if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {
|
||||
if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||
|
||||
TheLine.Type == LT_ImportStatement) {
|
||||
LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
|
||||
while (State.NextToken) {
|
||||
formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);
|
||||
|
|
|
@ -33,8 +33,8 @@ class AnnotatingParser {
|
|||
public:
|
||||
AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line,
|
||||
const AdditionalKeywords &Keywords)
|
||||
: Style(Style), Line(Line), CurrentToken(Line.First),
|
||||
KeywordVirtualFound(false), AutoFound(false), Keywords(Keywords) {
|
||||
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
|
||||
Keywords(Keywords) {
|
||||
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
|
||||
resetTokenMetadata(CurrentToken);
|
||||
}
|
||||
|
@ -536,14 +536,6 @@ private:
|
|||
CurrentToken->Type = TT_ImplicitStringLiteral;
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
while (CurrentToken) {
|
||||
if (CurrentToken->isNot(tok::comment))
|
||||
// Mark these tokens as "implicit" string literals, so that
|
||||
// they are not split or line-wrapped.
|
||||
CurrentToken->Type = TT_ImplicitStringLiteral;
|
||||
next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,23 +562,25 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void parsePreprocessorDirective() {
|
||||
LineType parsePreprocessorDirective() {
|
||||
LineType Type = LT_PreprocessorDirective;
|
||||
next();
|
||||
if (!CurrentToken)
|
||||
return;
|
||||
return Type;
|
||||
if (CurrentToken->Tok.is(tok::numeric_constant)) {
|
||||
CurrentToken->SpacesRequiredBefore = 1;
|
||||
return;
|
||||
return Type;
|
||||
}
|
||||
// Hashes in the middle of a line can lead to any strange token
|
||||
// sequence.
|
||||
if (!CurrentToken->Tok.getIdentifierInfo())
|
||||
return;
|
||||
return Type;
|
||||
switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
|
||||
case tok::pp_include:
|
||||
case tok::pp_import:
|
||||
next();
|
||||
parseIncludeDirective();
|
||||
Type = LT_ImportStatement;
|
||||
break;
|
||||
case tok::pp_error:
|
||||
case tok::pp_warning:
|
||||
|
@ -605,13 +599,13 @@ private:
|
|||
}
|
||||
while (CurrentToken)
|
||||
next();
|
||||
return Type;
|
||||
}
|
||||
|
||||
public:
|
||||
LineType parseLine() {
|
||||
if (CurrentToken->is(tok::hash)) {
|
||||
parsePreprocessorDirective();
|
||||
return LT_PreprocessorDirective;
|
||||
return parsePreprocessorDirective();
|
||||
}
|
||||
|
||||
// Directly allow to 'import <string-literal>' to support protocol buffer
|
||||
|
@ -622,24 +616,30 @@ public:
|
|||
CurrentToken->Next) {
|
||||
next();
|
||||
parseIncludeDirective();
|
||||
return LT_Other;
|
||||
return LT_ImportStatement;
|
||||
}
|
||||
|
||||
// If this line starts and ends in '<' and '>', respectively, it is likely
|
||||
// part of "#define <a/b.h>".
|
||||
if (CurrentToken->is(tok::less) && Line.Last->is(tok::greater)) {
|
||||
parseIncludeDirective();
|
||||
return LT_Other;
|
||||
return LT_ImportStatement;
|
||||
}
|
||||
|
||||
bool KeywordVirtualFound = false;
|
||||
bool ImportStatement = false;
|
||||
while (CurrentToken) {
|
||||
if (CurrentToken->is(tok::kw_virtual))
|
||||
KeywordVirtualFound = true;
|
||||
if (IsImportStatement(*CurrentToken))
|
||||
ImportStatement = true;
|
||||
if (!consumeToken())
|
||||
return LT_Invalid;
|
||||
}
|
||||
if (KeywordVirtualFound)
|
||||
return LT_VirtualFunctionDecl;
|
||||
if (ImportStatement)
|
||||
return LT_ImportStatement;
|
||||
|
||||
if (Line.First->Type == TT_ObjCMethodSpecifier) {
|
||||
if (Contexts.back().FirstObjCSelectorName)
|
||||
|
@ -652,6 +652,16 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
bool IsImportStatement(const FormatToken &Tok) {
|
||||
// FIXME: Closure-library specific stuff should not be hard-coded but be
|
||||
// configurable.
|
||||
return Style.Language == FormatStyle::LK_JavaScript &&
|
||||
Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) &&
|
||||
Tok.Next->Next && (Tok.Next->Next->TokenText == "module" ||
|
||||
Tok.Next->Next->TokenText == "require" ||
|
||||
Tok.Next->Next->TokenText == "provide");
|
||||
}
|
||||
|
||||
void resetTokenMetadata(FormatToken *Token) {
|
||||
if (!Token)
|
||||
return;
|
||||
|
@ -1066,7 +1076,6 @@ private:
|
|||
const FormatStyle &Style;
|
||||
AnnotatedLine &Line;
|
||||
FormatToken *CurrentToken;
|
||||
bool KeywordVirtualFound;
|
||||
bool AutoFound;
|
||||
const AdditionalKeywords &Keywords;
|
||||
};
|
||||
|
|
|
@ -27,12 +27,13 @@ namespace format {
|
|||
|
||||
enum LineType {
|
||||
LT_Invalid,
|
||||
LT_Other,
|
||||
LT_PreprocessorDirective,
|
||||
LT_VirtualFunctionDecl,
|
||||
LT_ImportStatement,
|
||||
LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
|
||||
LT_ObjCMethodDecl,
|
||||
LT_ObjCProperty // An @property line.
|
||||
LT_ObjCProperty, // An @property line.
|
||||
LT_Other,
|
||||
LT_PreprocessorDirective,
|
||||
LT_VirtualFunctionDecl
|
||||
};
|
||||
|
||||
class AnnotatedLine {
|
||||
|
|
|
@ -418,6 +418,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
|
|||
}
|
||||
|
||||
static bool IsGoogScope(const UnwrappedLine &Line) {
|
||||
// FIXME: Closure-library specific stuff should not be hard-coded but be
|
||||
// configurable.
|
||||
if (Line.Tokens.size() < 4)
|
||||
return false;
|
||||
auto I = Line.Tokens.begin();
|
||||
|
|
|
@ -158,6 +158,17 @@ TEST_F(FormatTestJS, GoogScopes) {
|
|||
"}); // goog.scope");
|
||||
}
|
||||
|
||||
TEST_F(FormatTestJS, GoogModules) {
|
||||
verifyFormat("goog.module('this.is.really.absurdly.long');",
|
||||
getGoogleJSStyleWithColumns(40));
|
||||
verifyFormat("goog.require('this.is.really.absurdly.long');",
|
||||
getGoogleJSStyleWithColumns(40));
|
||||
verifyFormat("goog.provide('this.is.really.absurdly.long');",
|
||||
getGoogleJSStyleWithColumns(40));
|
||||
verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
|
||||
getGoogleJSStyleWithColumns(40));
|
||||
}
|
||||
|
||||
TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
|
||||
verifyFormat("function outer1(a, b) {\n"
|
||||
" function inner1(a, b) { return a; }\n"
|
||||
|
|
Loading…
Reference in New Issue