blob: edb6d4d4381d113f27f4ea7518e0eab580ef7edb [file] [log] [blame]
//===- Nodes.h - syntax nodes for C/C++ grammar constructs ----*- C++ -*-=====//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Syntax tree nodes for C, C++ and Objective-C grammar constructs.
//
// Nodes provide access to their syntactic components, e.g. IfStatement provides
// a way to get its condition, then and else branches, tokens for 'if' and
// 'else' keywords.
// When using the accessors, please assume they can return null. This happens
// because:
// - the corresponding subnode is optional in the C++ grammar, e.g. an else
// branch of an if statement,
// - syntactic errors occurred while parsing the corresponding subnode.
// One notable exception is "introducer" keywords, e.g. the accessor for the
// 'if' keyword of an if statement will never return null.
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLING_SYNTAX_NODES_H
#define LLVM_CLANG_TOOLING_SYNTAX_NODES_H
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/Token.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Tooling/Syntax/Tree.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace syntax {
/// A kind of a syntax node, used for implementing casts. The ordering and
/// blocks of enumerator constants must correspond to the inheritance hierarchy
/// of syntax::Node.
enum class NodeKind : uint16_t {
#define CONCRETE_NODE(Kind, Base) Kind,
#include "clang/Tooling/Syntax/Nodes.inc"
};
/// For debugging purposes.
raw_ostream &operator<<(raw_ostream &OS, NodeKind K);
/// A relation between a parent and child node, e.g. 'left-hand-side of
/// a binary expression'. Used for implementing accessors.
///
/// In general `NodeRole`s should be named the same as their accessors.
///
/// Some roles describe parent/child relations that occur multiple times in
/// language grammar. We define only one role to describe all instances of such
/// recurring relations. For example, grammar for both "if" and "while"
/// statements requires an opening paren and a closing paren. The opening
/// paren token is assigned the OpenParen role regardless of whether it appears
/// as a child of IfStatement or WhileStatement node. More generally, when
/// grammar requires a certain fixed token (like a specific keyword, or an
/// opening paren), we define a role for this token and use it across all
/// grammar rules with the same requirement. Names of such reusable roles end
/// with a ~Token or a ~Keyword suffix.
enum class NodeRole : uint8_t {
// Roles common to multiple node kinds.
/// A node without a parent
Detached,
/// Children of an unknown semantic nature, e.g. skipped tokens, comments.
Unknown,
/// An opening parenthesis in argument lists and blocks, e.g. '{', '(', etc.
OpenParen,
/// A closing parenthesis in argument lists and blocks, e.g. '}', ')', etc.
CloseParen,
/// A keywords that introduces some grammar construct, e.g. 'if', 'try', etc.
IntroducerKeyword,
/// A token that represents a literal, e.g. 'nullptr', '1', 'true', etc.
LiteralToken,
/// Tokens or Keywords.
ArrowToken,
ExternKeyword,
TemplateKeyword,
/// An inner statement for those that have only a single child of kind
/// statement, e.g. loop body for while, for, etc; inner statement for case,
/// default, etc.
BodyStatement,
/// List API roles.
ListElement,
ListDelimiter,
// Roles specific to particular node kinds.
OperatorToken,
Operand,
LeftHandSide,
RightHandSide,
ReturnValue,
CaseValue,
ThenStatement,
ElseKeyword,
ElseStatement,
Expression,
Statement,
Condition,
Message,
Declarator,
Declaration,
Size,
Parameters,
TrailingReturn,
UnqualifiedId,
Qualifier,
SubExpression,
Object,
AccessToken,
Member,
Callee,
Arguments,
Declarators
};
/// For debugging purposes.
raw_ostream &operator<<(raw_ostream &OS, NodeRole R);
#include "clang/Tooling/Syntax/NodeClasses.inc"
/// Models a `nested-name-specifier`. C++ [expr.prim.id.qual]
/// e.g. the `std::vector<int>::` in `std::vector<int>::size`.
class NestedNameSpecifier final : public List {
public:
NestedNameSpecifier() : List(NodeKind::NestedNameSpecifier) {}
static bool classof(const Node *N);
std::vector<NameSpecifier *> getSpecifiers();
std::vector<List::ElementAndDelimiter<syntax::NameSpecifier>>
getSpecifiersAndDoubleColons();
};
/// Models an `unqualified-id`. C++ [expr.prim.id.unqual]
/// e.g. the `size` in `std::vector<int>::size`.
class UnqualifiedId final : public Tree {
public:
UnqualifiedId() : Tree(NodeKind::UnqualifiedId) {}
static bool classof(const Node *N);
};
/// An expression of an unknown kind, i.e. one not currently handled by the
/// syntax tree.
class UnknownExpression final : public Expression {
public:
UnknownExpression() : Expression(NodeKind::UnknownExpression) {}
static bool classof(const Node *N);
};
/// Models arguments of a function call.
/// call-arguments:
/// delimited_list(expression, ',')
/// Note: This construct is a simplification of the grammar rule for
/// `expression-list`, that is used in the definition of `call-expression`
class CallArguments final : public List {
public:
CallArguments() : List(NodeKind::CallArguments) {}
static bool classof(const Node *N);
std::vector<Expression *> getArguments();
std::vector<List::ElementAndDelimiter<Expression>> getArgumentsAndCommas();
};
/// An abstract class for prefix and postfix unary operators.
class UnaryOperatorExpression : public Expression {
public:
UnaryOperatorExpression(NodeKind K) : Expression(K) {}
static bool classof(const Node *N);
Leaf *getOperatorToken();
Expression *getOperand();
};
/// <operator> <operand>
///
/// For example:
/// +a -b
/// !c not c
/// ~d compl d
/// *e &f
/// ++h --h
/// __real i __imag i
class PrefixUnaryOperatorExpression final : public UnaryOperatorExpression {
public:
PrefixUnaryOperatorExpression()
: UnaryOperatorExpression(NodeKind::PrefixUnaryOperatorExpression) {}
static bool classof(const Node *N);
};
/// <operand> <operator>
///
/// For example:
/// a++
/// b--
class PostfixUnaryOperatorExpression final : public UnaryOperatorExpression {
public:
PostfixUnaryOperatorExpression()
: UnaryOperatorExpression(NodeKind::PostfixUnaryOperatorExpression) {}
static bool classof(const Node *N);
};
/// <lhs> <operator> <rhs>
///
/// For example:
/// a + b
/// a bitor 1
/// a |= b
/// a and_eq b
class BinaryOperatorExpression final : public Expression {
public:
BinaryOperatorExpression() : Expression(NodeKind::BinaryOperatorExpression) {}
static bool classof(const Node *N);
Expression *getLhs();
Leaf *getOperatorToken();
Expression *getRhs();
};
/// An abstract node for C++ statements, e.g. 'while', 'if', etc.
/// FIXME: add accessors for semicolon of statements that have it.
class Statement : public Tree {
public:
Statement(NodeKind K) : Tree(K) {}
static bool classof(const Node *N);
};
/// A statement of an unknown kind, i.e. one not currently handled by the syntax
/// tree.
class UnknownStatement final : public Statement {
public:
UnknownStatement() : Statement(NodeKind::UnknownStatement) {}
static bool classof(const Node *N);
};
/// E.g. 'int a, b = 10;'
class DeclarationStatement final : public Statement {
public:
DeclarationStatement() : Statement(NodeKind::DeclarationStatement) {}
static bool classof(const Node *N);
};
/// The no-op statement, i.e. ';'.
class EmptyStatement final : public Statement {
public:
EmptyStatement() : Statement(NodeKind::EmptyStatement) {}
static bool classof(const Node *N);
};
/// switch (<cond>) <body>
class SwitchStatement final : public Statement {
public:
SwitchStatement() : Statement(NodeKind::SwitchStatement) {}
static bool classof(const Node *N);
Leaf *getSwitchKeyword();
Statement *getBody();
};
/// case <value>: <body>
class CaseStatement final : public Statement {
public:
CaseStatement() : Statement(NodeKind::CaseStatement) {}
static bool classof(const Node *N);
Leaf *getCaseKeyword();
Expression *getCaseValue();
Statement *getBody();
};
/// default: <body>
class DefaultStatement final : public Statement {
public:
DefaultStatement() : Statement(NodeKind::DefaultStatement) {}
static bool classof(const Node *N);
Leaf *getDefaultKeyword();
Statement *getBody();
};
/// if (cond) <then-statement> else <else-statement>
/// FIXME: add condition that models 'expression or variable declaration'
class IfStatement final : public Statement {
public:
IfStatement() : Statement(NodeKind::IfStatement) {}
static bool classof(const Node *N);
Leaf *getIfKeyword();
Statement *getThenStatement();
Leaf *getElseKeyword();
Statement *getElseStatement();
};
/// for (<init>; <cond>; <increment>) <body>
class ForStatement final : public Statement {
public:
ForStatement() : Statement(NodeKind::ForStatement) {}
static bool classof(const Node *N);
Leaf *getForKeyword();
Statement *getBody();
};
/// while (<cond>) <body>
class WhileStatement final : public Statement {
public:
WhileStatement() : Statement(NodeKind::WhileStatement) {}
static bool classof(const Node *N);
Leaf *getWhileKeyword();
Statement *getBody();
};
/// continue;
class ContinueStatement final : public Statement {
public:
ContinueStatement() : Statement(NodeKind::ContinueStatement) {}
static bool classof(const Node *N);
Leaf *getContinueKeyword();
};
/// break;
class BreakStatement final : public Statement {
public:
BreakStatement() : Statement(NodeKind::BreakStatement) {}
static bool classof(const Node *N);
Leaf *getBreakKeyword();
};
/// return <expr>;
/// return;
class ReturnStatement final : public Statement {
public:
ReturnStatement() : Statement(NodeKind::ReturnStatement) {}
static bool classof(const Node *N);
Leaf *getReturnKeyword();
Expression *getReturnValue();
};
/// for (<decl> : <init>) <body>
class RangeBasedForStatement final : public Statement {
public:
RangeBasedForStatement() : Statement(NodeKind::RangeBasedForStatement) {}
static bool classof(const Node *N);
Leaf *getForKeyword();
Statement *getBody();
};
/// Expression in a statement position, e.g. functions calls inside compound
/// statements or inside a loop body.
class ExpressionStatement final : public Statement {
public:
ExpressionStatement() : Statement(NodeKind::ExpressionStatement) {}
static bool classof(const Node *N);
Expression *getExpression();
};
/// { statement1; statement2; … }
class CompoundStatement final : public Statement {
public:
CompoundStatement() : Statement(NodeKind::CompoundStatement) {}
static bool classof(const Node *N);
Leaf *getLbrace();
/// FIXME: use custom iterator instead of 'vector'.
std::vector<Statement *> getStatements();
Leaf *getRbrace();
};
/// A declaration that can appear at the top-level. Note that this does *not*
/// correspond 1-to-1 to clang::Decl. Syntax trees distinguish between top-level
/// declarations (e.g. namespace definitions) and declarators (e.g. variables,
/// typedefs, etc.). Declarators are stored inside SimpleDeclaration.
class Declaration : public Tree {
public:
Declaration(NodeKind K) : Tree(K) {}
static bool classof(const Node *N);
};
/// Declaration of an unknown kind, e.g. not yet supported in syntax trees.
class UnknownDeclaration final : public Declaration {
public:
UnknownDeclaration() : Declaration(NodeKind::UnknownDeclaration) {}
static bool classof(const Node *N);
};
/// A semicolon in the top-level context. Does not declare anything.
class EmptyDeclaration final : public Declaration {
public:
EmptyDeclaration() : Declaration(NodeKind::EmptyDeclaration) {}
static bool classof(const Node *N);
};
/// static_assert(<condition>, <message>)
/// static_assert(<condition>)
class StaticAssertDeclaration final : public Declaration {
public:
StaticAssertDeclaration() : Declaration(NodeKind::StaticAssertDeclaration) {}
static bool classof(const Node *N);
Expression *getCondition();
Expression *getMessage();
};
/// extern <string-literal> declaration
/// extern <string-literal> { <decls> }
class LinkageSpecificationDeclaration final : public Declaration {
public:
LinkageSpecificationDeclaration()
: Declaration(NodeKind::LinkageSpecificationDeclaration) {}
static bool classof(const Node *N);
};
class DeclaratorList final : public List {
public:
DeclaratorList() : List(NodeKind::DeclaratorList) {}
static bool classof(const Node *N);
std::vector<SimpleDeclarator *> getDeclarators();
std::vector<List::ElementAndDelimiter<syntax::SimpleDeclarator>>
getDeclaratorsAndCommas();
};
/// Groups multiple declarators (e.g. variables, typedefs, etc.) together. All
/// grouped declarators share the same declaration specifiers (e.g. 'int' or
/// 'typedef').
class SimpleDeclaration final : public Declaration {
public:
SimpleDeclaration() : Declaration(NodeKind::SimpleDeclaration) {}
static bool classof(const Node *N);
/// FIXME: use custom iterator instead of 'vector'.
std::vector<SimpleDeclarator *> getDeclarators();
};
/// template <template-parameters> <declaration>
class TemplateDeclaration final : public Declaration {
public:
TemplateDeclaration() : Declaration(NodeKind::TemplateDeclaration) {}
static bool classof(const Node *N);
Leaf *getTemplateKeyword();
Declaration *getDeclaration();
};
/// template <declaration>
/// Examples:
/// template struct X<int>
/// template void foo<int>()
/// template int var<double>
class ExplicitTemplateInstantiation final : public Declaration {
public:
ExplicitTemplateInstantiation()
: Declaration(NodeKind::ExplicitTemplateInstantiation) {}
static bool classof(const Node *N);
Leaf *getTemplateKeyword();
Leaf *getExternKeyword();
Declaration *getDeclaration();
};
/// namespace <name> { <decls> }
class NamespaceDefinition final : public Declaration {
public:
NamespaceDefinition() : Declaration(NodeKind::NamespaceDefinition) {}
static bool classof(const Node *N);
};
/// namespace <name> = <namespace-reference>
class NamespaceAliasDefinition final : public Declaration {
public:
NamespaceAliasDefinition()
: Declaration(NodeKind::NamespaceAliasDefinition) {}
static bool classof(const Node *N);
};
/// using namespace <name>
class UsingNamespaceDirective final : public Declaration {
public:
UsingNamespaceDirective() : Declaration(NodeKind::UsingNamespaceDirective) {}
static bool classof(const Node *N);
};
/// using <scope>::<name>
/// using typename <scope>::<name>
class UsingDeclaration final : public Declaration {
public:
UsingDeclaration() : Declaration(NodeKind::UsingDeclaration) {}
static bool classof(const Node *N);
};
/// using <name> = <type>
class TypeAliasDeclaration final : public Declaration {
public:
TypeAliasDeclaration() : Declaration(NodeKind::TypeAliasDeclaration) {}
static bool classof(const Node *N);
};
/// Covers a name, an initializer and a part of the type outside declaration
/// specifiers. Examples are:
/// `*a` in `int *a`
/// `a[10]` in `int a[10]`
/// `*a = nullptr` in `int *a = nullptr`
/// Declarators can be unnamed too:
/// `**` in `new int**`
/// `* = nullptr` in `void foo(int* = nullptr)`
/// Most declarators you encounter are instances of SimpleDeclarator. They may
/// contain an inner declarator inside parentheses, we represent it as
/// ParenDeclarator. E.g.
/// `(*a)` in `int (*a) = 10`
class Declarator : public Tree {
public:
Declarator(NodeKind K) : Tree(K) {}
static bool classof(const Node *N);
};
/// A top-level declarator without parentheses. See comment of Declarator for
/// more details.
class SimpleDeclarator final : public Declarator {
public:
SimpleDeclarator() : Declarator(NodeKind::SimpleDeclarator) {}
static bool classof(const Node *N);
};
/// Declarator inside parentheses.
/// E.g. `(***a)` from `int (***a) = nullptr;`
/// See comment of Declarator for more details.
class ParenDeclarator final : public Declarator {
public:
ParenDeclarator() : Declarator(NodeKind::ParenDeclarator) {}
static bool classof(const Node *N);
Leaf *getLparen();
Leaf *getRparen();
};
/// Array size specified inside a declarator.
/// E.g:
/// `[10]` in `int a[10];`
/// `[static 10]` in `void f(int xs[static 10]);`
class ArraySubscript final : public Tree {
public:
ArraySubscript() : Tree(NodeKind::ArraySubscript) {}
static bool classof(const Node *N);
// TODO: add an accessor for the "static" keyword.
Leaf *getLbracket();
Expression *getSize();
Leaf *getRbracket();
};
/// Trailing return type after the parameter list, including the arrow token.
/// E.g. `-> int***`.
class TrailingReturnType final : public Tree {
public:
TrailingReturnType() : Tree(NodeKind::TrailingReturnType) {}
static bool classof(const Node *N);
// TODO: add accessors for specifiers.
Leaf *getArrowToken();
// FIXME: This should be a `type-id` following the grammar. Fix this once we
// have a representation of `type-id`s.
SimpleDeclarator *getDeclarator();
};
/// Models a `parameter-declaration-list` which appears within
/// `parameters-and-qualifiers`. See C++ [dcl.fct]
class ParameterDeclarationList final : public List {
public:
ParameterDeclarationList() : List(NodeKind::ParameterDeclarationList) {}
static bool classof(const Node *N);
std::vector<SimpleDeclaration *> getParameterDeclarations();
std::vector<List::ElementAndDelimiter<syntax::SimpleDeclaration>>
getParametersAndCommas();
};
/// Parameter list for a function type and a trailing return type, if the
/// function has one.
/// E.g.:
/// `(int a) volatile ` in `int foo(int a) volatile;`
/// `(int a) &&` in `int foo(int a) &&;`
/// `() -> int` in `auto foo() -> int;`
/// `() const` in `int foo() const;`
/// `() noexcept` in `int foo() noexcept;`
/// `() throw()` in `int foo() throw();`
///
/// (!) override doesn't belong here.
class ParametersAndQualifiers final : public Tree {
public:
ParametersAndQualifiers() : Tree(NodeKind::ParametersAndQualifiers) {}
static bool classof(const Node *N);
Leaf *getLparen();
ParameterDeclarationList *getParameters();
Leaf *getRparen();
TrailingReturnType *getTrailingReturn();
};
/// Member pointer inside a declarator
/// E.g. `X::*` in `int X::* a = 0;`
class MemberPointer final : public Tree {
public:
MemberPointer() : Tree(NodeKind::MemberPointer) {}
static bool classof(const Node *N);
};
#define CONCRETE_NODE(Kind, Base) \
inline bool Kind::classof(const Node *N) { \
return N->getKind() == NodeKind::Kind; \
}
#define ABSTRACT_NODE(Kind, Base, First, Last) \
inline bool Kind::classof(const Node *N) { \
return N->getKind() >= NodeKind::First && N->getKind() <= NodeKind::Last; \
}
#include "clang/Tooling/Syntax/Nodes.inc"
} // namespace syntax
} // namespace clang
#endif