diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -45,6 +45,7 @@ BinaryOperatorExpression, CxxNullPtrExpression, IntegerLiteralExpression, + IdExpression, // Statements. UnknownStatement, @@ -84,7 +85,10 @@ ArraySubscript, TrailingReturnType, ParametersAndQualifiers, - MemberPointer + MemberPointer, + NestedNameSpecifier, + NameSpecifier, + UnqualifiedId }; /// For debugging purposes. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K); @@ -187,6 +191,108 @@ } }; +/// A sequence of these specifiers makes a `nested-name-specifier`. +/// e.g. the `std::` or `vector::` in `std::vector::size`. +class NameSpecifier final : public Tree { +private: +public: + NameSpecifier() : Tree(NodeKind::NameSpecifier) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::NameSpecifier; + } + + // See discussion about OR relation in `UnqualifiedId` + NodeKind getChildKind(); + syntax::Leaf *getIdentifier(); + syntax::Leaf *getNamespaceName(); + //(...) + + // Should we create accessors to everything? + syntax::Leaf *doubleCommaToken(); +}; + +/// Models a `nested-name-specifier`. C++ [expr.prim.id.qual] +/// e.g. the `std::vector::` in `std::vector::size`. +class NestedNameSpecifier final : public Tree { +public: + NestedNameSpecifier() : Tree(NodeKind::NestedNameSpecifier) {} + static bool classof(const Node *N) { + return N->kind() <= NodeKind::NestedNameSpecifier; + } + std::vector specifiers(); +}; + +// Models `operator-function-id`. To be implemented, not interesting for +// discussion +class OperatorFunctionId; +// Models `identifier`. This is merely a token. +class Identifier; + +/// Models an `unqualified-id`, e.g. the `size` in `std::vector::size`. +// C++ [expr.prim.id.unqual] +// unqualified-id: +// identifier +// operator-function-id +// conversion-function-id +// literal-operator-id +// ~ type-name +// ~ decltype-specifier +// template-id +class UnqualifiedId final : public Tree { + // As {`identifier`, `operator-function-id`, ...} appear in other parts of the + // grammar - `template-id` appears almost everywhere - we implement them as + // standalone nodes instead of derived from `unqualified-id`. We encode the + // relation `unqualified-id` = {`identifier` OR `operator-function-id` OR ...} + // through a parent-child relation and to discover which child we have we + // check the `NodeKind` of the child. +private: +public: + UnqualifiedId() : Tree(NodeKind::UnqualifiedId) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::UnqualifiedId; + } + NodeKind getChildKind(); + + // The way to use the API would be to call `getChildKind()` + // and then use the appropriate accessor according to the kind of the child. + syntax::Identifier * + getIdentifier(); // Drawback: Identifier is merely a Token, as such we + // could've use a `syntax::Leaf` + syntax::OperatorFunctionId *getOperatorFunctionId(); + // (...) +}; + +/// Models an `id-expression`, e.g. `std::vector::size`. +/// C++ [expr.prim.id] +/// id-expression: +/// unqualified-id +/// qualified-id +/// qualified-id: +/// nested-name-specifier template_opt unqualified-id +/// For simplicity we use: +/// id-expression: +/// nested-name-specifier_opt template_opt unqualified-id +/// That is a bit more general than the grammar rule and allows forbidden +/// syntax. That's ok, it is not our duty to verify the syntax of the program +class IdExpression final : public Expression { +public: + IdExpression() : Expression(NodeKind::IdExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::IdExpression; + } + // `qualifier` and `templateKeyword` are optional children of + // id-expression whereas `id` is a required child. + // How to make this distinction clear both to the reader and to the compiler? + // For children that are: + // * required: use reference; optional: use pointer + // * required: reference; optional: optional reference + // We could also use attributes to document that a pointer is not null + syntax::NestedNameSpecifier *qualifier(); + syntax::Leaf *templateKeyword(); + + syntax::UnqualifiedId *id(); +}; + /// C++11 'nullptr' expression. class CxxNullPtrExpression final : public Expression { public: