| //===- 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 |