//===--- TokenAnnotator.cpp - Format C++ code -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file implements a token annotator, i.e. creates
/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
///
//===----------------------------------------------------------------------===//
#include "TokenAnnotator.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
namespace clang {
namespace format {
/// \brief Returns if a token is an Objective-C selector name.
///
/// For example, "bar" is a selector name in [foo bar:(4 + 5)].
static bool isObjCSelectorName(const AnnotatedToken &Tok) {
return Tok.is(tok::identifier) && !Tok.Children.empty() &&
Tok.Children[0].is(tok::colon) &&
Tok.Children[0].Type == TT_ObjCMethodExpr;
}
static bool isBinaryOperator(const AnnotatedToken &Tok) {
// Comma is a binary operator, but does not behave as such wrt. formatting.
return getPrecedence(Tok) > prec::Comma;
}
// Returns the previous token ignoring comments.
static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) {
const AnnotatedToken *PrevToken = Tok.Parent;
while (PrevToken != NULL && PrevToken->is(tok::comment))
PrevToken = PrevToken->Parent;
return PrevToken;
}
// Returns the next token ignoring comments.
static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) {
if (Tok.Children.empty())
return NULL;
const AnnotatedToken *NextToken = &Tok.Children[0];
while (NextToken->is(tok::comment)) {
if (NextToken->Children.empty())
return NULL;
NextToken = &NextToken->Children[0];
}
return NextToken;
}
/// \brief A parser that gathers additional information about tokens.
///
/// The \c TokenAnnotator tries to matches parenthesis and square brakets and
/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
/// into template parameter lists.
class AnnotatingParser {
public:
AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line)
: SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
KeywordVirtualFound(false), ColonIsObjCMethodExpr(false),
ColonIsForRangeExpr(false), IsExpression(false),
LookForFunctionName(Line.MustBeDeclaration), BindingStrength(1) {
}
/// \brief A helper class to manage AnnotatingParser::ColonIsObjCMethodExpr.
struct ObjCSelectorRAII {
AnnotatingParser &P;
bool ColonWasObjCMethodExpr;
ObjCSelectorRAII(AnnotatingParser &P)
: P(P), ColonWasObjCMethodExpr(P.ColonIsObjCMethodExpr) {
}
~ObjCSelectorRAII() { P.ColonIsObjCMethodExpr = ColonWasObjCMethodExpr; }
void markStart(AnnotatedToken &Left) {
P.ColonIsObjCMethodExpr = true;
Left.Type = TT_ObjCMethodExpr;
}
void markEnd(AnnotatedToken &Right) { Right.Type = TT_ObjCMethodExpr; }
};
struct ScopedBindingStrengthIncrease {
AnnotatingParser &P;
unsigned Increase;
ScopedBindingStrengthIncrease(AnnotatingParser &P, unsigned Increase)
: P(P), Increase(Increase) {
P.BindingStrength += Increase;
}
~ScopedBindingStrengthIncrease() { P.BindingStrength -= Increase; }
};
bool parseAngle() {
if (CurrentToken == NULL)
return false;
ScopedBindingStrengthIncrease Increase(*this, 10);
AnnotatedToken *Left = CurrentToken->Parent;
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::greater)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
CurrentToken->Type = TT_TemplateCloser;
next();
return true;
}
if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square) ||
CurrentToken->is(tok::r_brace))
return false;
if (CurrentToken->is(tok::pipepipe) || CurrentToken->is(tok::ampamp) ||
CurrentToken->is(tok::question) || CurrentToken->is(tok::colon))
return false;
if (CurrentToken->is(tok::comma))
++Left->ParameterCount;
if (!consumeToken())
return false;
}
return false;
}
bool parseParens(bool LookForDecls = false) {
if (CurrentToken == NULL)
return false;
ScopedBindingStrengthIncrease Increase(*this, 1);
bool StartsObjCMethodExpr = false;
AnnotatedToken *Left = CurrentToken->Parent;
if (CurrentToken