}
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
SourceManager &SourceMgr,
WhitespaceManager &Whitespaces,
encoding::Encoding Encoding,
bool BinPackInconclusiveFunctions)
- : Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces),
- Encoding(Encoding),
+ : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr),
+ Whitespaces(Whitespaces), Encoding(Encoding),
BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
CommentPragmasRegex(Style.CommentPragmas) {}
NextNonComment = &Current;
// Java specific bits.
- if (Style.Language == FormatStyle::LK_Java && Current.is(tok::identifier) &&
- (Current.TokenText == "implements" || Current.TokenText == "extends"))
+ if (Style.Language == FormatStyle::LK_Java &&
+ Current.isOneOf(Keywords.kw_implements, Keywords.kw_extends))
return std::max(State.Stack.back().LastSpace,
State.Stack.back().Indent + Style.ContinuationIndentWidth);
}
State.Stack[State.Stack.size() - 2].JSFunctionInlined = false;
}
- if (Current.TokenText == "function")
+ if (Current.is(Keywords.kw_function))
State.Stack.back().JSFunctionInlined =
!Newline && Previous && Previous->Type != TT_DictLiteral &&
Previous->Type != TT_ConditionalExpr &&
#define LLVM_CLANG_LIB_FORMAT_CONTINUATIONINDENTER_H
#include "Encoding.h"
+#include "FormatToken.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"
public:
/// \brief Constructs a \c ContinuationIndenter to format \p Line starting in
/// column \p FirstIndent.
- ContinuationIndenter(const FormatStyle &Style, SourceManager &SourceMgr,
- WhitespaceManager &Whitespaces,
+ ContinuationIndenter(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
+ SourceManager &SourceMgr, WhitespaceManager &Whitespaces,
encoding::Encoding Encoding,
bool BinPackInconclusiveFunctions);
bool nextIsMultilineString(const LineState &State);
FormatStyle Style;
+ const AdditionalKeywords &Keywords;
SourceManager &SourceMgr;
WhitespaceManager &Whitespaces;
encoding::Encoding Encoding;
FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle &Style,
encoding::Encoding Encoding)
: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false),
- Column(0), TrailingWhitespace(0),
- SourceMgr(SourceMgr), ID(ID), Style(Style),
- IdentTable(getFormattingLangOpts(Style)), Encoding(Encoding),
- FirstInLineIndex(0), FormattingDisabled(false) {
+ Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
+ Style(Style), IdentTable(getFormattingLangOpts(Style)),
+ Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0),
+ FormattingDisabled(false) {
Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr,
getFormattingLangOpts(Style)));
Lex->SetKeepWhitespaceMode(true);
return Tokens;
}
- IdentifierTable &getIdentTable() { return IdentTable; }
+ const AdditionalKeywords &getKeywords() { return Keywords; }
private:
void tryMergePreviousTokens() {
FileID ID;
FormatStyle &Style;
IdentifierTable IdentTable;
+ AdditionalKeywords Keywords;
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
// Index (in 'Tokens') of the last token that starts a new line.
tooling::Replacements Result;
FormatTokenLexer Tokens(SourceMgr, ID, Style, Encoding);
- UnwrappedLineParser Parser(Style, Tokens.lex(), *this);
+ UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(),
+ *this);
bool StructuralError = Parser.parse();
assert(UnwrappedLines.rbegin()->empty());
for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE;
tooling::Replacements format(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
bool StructuralError, FormatTokenLexer &Tokens) {
- TokenAnnotator Annotator(Style, Tokens.getIdentTable().get("in"));
+ TokenAnnotator Annotator(Style, Tokens.getKeywords());
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Annotator.annotate(*AnnotatedLines[i]);
}
computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());
Annotator.setCommentLineLevels(AnnotatedLines);
- ContinuationIndenter Indenter(Style, SourceMgr, Whitespaces, Encoding,
+ ContinuationIndenter Indenter(Style, Tokens.getKeywords(), SourceMgr,
+ Whitespaces, Encoding,
BinPackInconclusiveFunctions);
UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
Formatter.format(AnnotatedLines, /*DryRun=*/false);
#ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKEN_H
#define LLVM_CLANG_LIB_FORMAT_FORMATTOKEN_H
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
+ bool is(const IdentifierInfo *II) const {
+ return II && II == Tok.getIdentifierInfo();
+ }
+
+ template <typename T>
+ bool isOneOf(T K1, T K2) const {
return is(K1) || is(K2);
}
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
+ template <typename T>
+ bool isOneOf(T K1, T K2, T K3) const {
return is(K1) || is(K2) || is(K3);
}
- bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
- tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
- tok::TokenKind K6 = tok::NUM_TOKENS,
- tok::TokenKind K7 = tok::NUM_TOKENS,
- tok::TokenKind K8 = tok::NUM_TOKENS,
- tok::TokenKind K9 = tok::NUM_TOKENS,
- tok::TokenKind K10 = tok::NUM_TOKENS,
- tok::TokenKind K11 = tok::NUM_TOKENS,
- tok::TokenKind K12 = tok::NUM_TOKENS) const {
+ template <typename T>
+ bool isOneOf(T K1, T K2, T K3, T K4, T K5 = tok::NUM_TOKENS,
+ T K6 = tok::NUM_TOKENS, T K7 = tok::NUM_TOKENS,
+ T K8 = tok::NUM_TOKENS, T K9 = tok::NUM_TOKENS,
+ T K10 = tok::NUM_TOKENS, T K11 = tok::NUM_TOKENS,
+ T K12 = tok::NUM_TOKENS) const {
return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
}
- bool isNot(tok::TokenKind Kind) const { return Tok.isNot(Kind); }
+ template <typename T>
+ bool isNot(T Kind) const {
+ return Tok.isNot(Kind);
+ }
+
bool isStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); }
bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
bool HasNestedBracedList;
};
+/// \brief Encapsulates keywords that are context sensitive or for languages not
+/// properly supported by Clang's lexer.
+struct AdditionalKeywords {
+ AdditionalKeywords(IdentifierTable &IdentTable) {
+ kw_in = &IdentTable.get("in");
+ kw_NS_ENUM = &IdentTable.get("NS_ENUM");
+
+ kw_finally = &IdentTable.get("finally");
+ kw_function = &IdentTable.get("function");
+ kw_var = &IdentTable.get("var");
+
+ kw_extends = &IdentTable.get("extends");
+ kw_implements = &IdentTable.get("implements");
+ kw_synchronized = &IdentTable.get("synchronized");
+ kw_throws = &IdentTable.get("throws");
+
+ kw_option = &IdentTable.get("option");
+ kw_optional = &IdentTable.get("optional");
+ kw_repeated = &IdentTable.get("repeated");
+ kw_required = &IdentTable.get("required");
+ kw_returns = &IdentTable.get("returns");
+ }
+
+ // ObjC context sensitive keywords.
+ IdentifierInfo *kw_in;
+ IdentifierInfo *kw_NS_ENUM;
+
+ // JavaScript keywords.
+ IdentifierInfo *kw_finally;
+ IdentifierInfo *kw_function;
+ IdentifierInfo *kw_var;
+
+ // Java keywords.
+ IdentifierInfo *kw_extends;
+ IdentifierInfo *kw_implements;
+ IdentifierInfo *kw_synchronized;
+ IdentifierInfo *kw_throws;
+
+ // Proto keywords.
+ IdentifierInfo *kw_option;
+ IdentifierInfo *kw_optional;
+ IdentifierInfo *kw_repeated;
+ IdentifierInfo *kw_required;
+ IdentifierInfo *kw_returns;
+};
+
} // namespace format
} // namespace clang
class AnnotatingParser {
public:
AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line,
- IdentifierInfo &Ident_in)
+ const AdditionalKeywords &Keywords)
: Style(Style), Line(Line), CurrentToken(Line.First),
- KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) {
+ KeywordVirtualFound(false), AutoFound(false), Keywords(Keywords) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata(CurrentToken);
}
if (Current->Type == TT_LambdaLSquare ||
(Current->is(tok::caret) && Current->Type == TT_UnaryOperator) ||
(Style.Language == FormatStyle::LK_JavaScript &&
- Current->TokenText == "function")) {
+ Current->is(Keywords.kw_function))) {
++Left->BlockParameterCount;
}
if (Current->is(tok::comma)) {
parseTemplateDeclaration();
break;
case tok::identifier:
- if (Line.First->is(tok::kw_for) &&
- Tok->Tok.getIdentifierInfo() == &Ident_in)
+ if (Line.First->is(tok::kw_for) && Tok->is(Keywords.kw_in))
Tok->Type = TT_ObjCForIn;
break;
case tok::comma:
Tok.Previous->Type == TT_TemplateCloser ||
Tok.Previous->isSimpleTypeSpecifier();
if (Style.Language == FormatStyle::LK_JavaScript && Tok.Next &&
- Tok.Next->TokenText == "in")
+ Tok.Next->is(Keywords.kw_in))
return false;
bool ParensCouldEndDecl =
Tok.Next && Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
FormatToken *CurrentToken;
bool KeywordVirtualFound;
bool AutoFound;
- IdentifierInfo &Ident_in;
+ const AdditionalKeywords &Keywords;
};
static int PrecedenceUnaryOperator = prec::PointerToMember + 1;
/// operator precedence.
class ExpressionParser {
public:
- ExpressionParser(const FormatStyle &Style, AnnotatedLine &Line)
- : Style(Style), Current(Line.First) {}
+ ExpressionParser(const FormatStyle &Style, const AdditionalKeywords &Keywords,
+ AnnotatedLine &Line)
+ : Style(Style), Keywords(Keywords), Current(Line.First) {}
/// \brief Parse expressions with the given operatore precedence.
void parse(int Precedence = 0) {
else if (Current->isOneOf(tok::period, tok::arrow))
return PrecedenceArrowAndPeriod;
else if (Style.Language == FormatStyle::LK_Java &&
- Current->is(tok::identifier) &&
- (Current->TokenText == "extends" ||
- Current->TokenText == "implements"))
+ Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements))
return 0;
}
return -1;
}
const FormatStyle &Style;
+ const AdditionalKeywords &Keywords;
FormatToken *Current;
};
I != E; ++I) {
annotate(**I);
}
- AnnotatingParser Parser(Style, Line, Ident_in);
+ AnnotatingParser Parser(Style, Line, Keywords);
Line.Type = Parser.parseLine();
if (Line.Type == LT_Invalid)
return;
- ExpressionParser ExprParser(Style, Line);
+ ExpressionParser ExprParser(Style, Keywords, Line);
ExprParser.parse();
if (Line.First->Type == TT_ObjCMethodSpecifier)
if (Left.Type == TT_LeadingJavaAnnotation)
return 1;
- if (Style.Language == FormatStyle::LK_Java && Right.TokenText == "implements")
+ if (Style.Language == FormatStyle::LK_Java &&
+ Right.is(Keywords.kw_implements))
return 2;
if (Right.isMemberAccess()) {
const FormatToken &Left = *Right.Previous;
if (Style.Language == FormatStyle::LK_Proto) {
if (Right.is(tok::period) &&
- (Left.TokenText == "optional" || Left.TokenText == "required" ||
- Left.TokenText == "repeated"))
+ Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
+ Keywords.kw_repeated))
return true;
if (Right.is(tok::l_paren) &&
- (Left.TokenText == "returns" || Left.TokenText == "option"))
+ Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Left.TokenText == "var")
+ if (Left.is(Keywords.kw_var))
return true;
} else if (Style.Language == FormatStyle::LK_Java) {
- if (Left.TokenText == "synchronized" && Right.is(tok::l_paren))
+ if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren))
return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
if (Left.is(tok::kw_static) && Right.Type == TT_TemplateOpener)
return true;
const FormatToken &Left = *Right.Previous;
if (Style.Language == FormatStyle::LK_Java) {
- if (Left.is(tok::identifier) &&
- (Left.TokenText == "throws" || Left.TokenText == "extends" ||
- Left.TokenText == "implements"))
+ if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
+ Keywords.kw_implements))
return false;
- if (Right.is(tok::identifier) &&
- (Right.TokenText == "throws" || Right.TokenText == "extends" ||
- Right.TokenText == "implements"))
+ if (Right.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
+ Keywords.kw_implements))
return true;
}
/// \c UnwrappedLine.
class TokenAnnotator {
public:
- TokenAnnotator(const FormatStyle &Style, IdentifierInfo &Ident_in)
- : Style(Style), Ident_in(Ident_in) {}
+ TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
+ : Style(Style), Keywords(Keywords) {}
/// \brief Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
const FormatStyle &Style;
- // Contextual keywords:
- IdentifierInfo &Ident_in;
+ const AdditionalKeywords &Keywords;
};
} // end namespace format
} // end anonymous namespace
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), StructuralError(false), Style(Style),
- Tokens(nullptr), Callback(Callback), AllTokens(Tokens),
- PPBranchLevel(-1) {}
+ Keywords(Keywords), Tokens(nullptr), Callback(Callback),
+ AllTokens(Tokens), PPBranchLevel(-1) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
break;
case tok::kw_typedef:
nextToken();
- // FIXME: Use the IdentifierTable instead.
- if (FormatTok->TokenText == "NS_ENUM")
+ if (FormatTok->is(Keywords.kw_NS_ENUM))
parseEnum();
break;
case tok::kw_struct:
// replace this by using parseAssigmentExpression() inside.
do {
if (Style.Language == FormatStyle::LK_JavaScript &&
- FormatTok->TokenText == "function") {
+ FormatTok->is(Keywords.kw_function)) {
tryToParseJSFunction();
continue;
}
break;
case tok::identifier:
if (Style.Language == FormatStyle::LK_JavaScript &&
- FormatTok->TokenText == "function")
+ FormatTok->is(Keywords.kw_function))
tryToParseJSFunction();
else
nextToken();
while (FormatTok->is(tok::kw_catch) ||
((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
- FormatTok->TokenText == "finally")) {
+ FormatTok->is(Keywords.kw_finally))) {
nextToken();
while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->is(tok::l_paren)) {
class UnwrappedLineParser {
public:
- UnwrappedLineParser(const FormatStyle &Style, ArrayRef<FormatToken *> Tokens,
+ UnwrappedLineParser(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
+ ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback);
/// Returns true in case of a structural error.
bool StructuralError;
const FormatStyle &Style;
+ const AdditionalKeywords &Keywords;
+
FormatTokenSource *Tokens;
UnwrappedLineConsumer &Callback;