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,11 @@ ArraySubscript, TrailingReturnType, ParametersAndQualifiers, - MemberPointer + MemberPointer, + NestedNameSpecifier, + NameSpecifier, + UnqualifiedId, + OperatorFunctionId, }; /// For debugging purposes. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K); @@ -187,6 +192,135 @@ } }; +/// A sequence of these specifiers make a `nested-name-specifier`. +/// e.g. the `std::` or `vector::` in `std::vector::size`. +class NameSpecifier final : public Tree { +private: + // See discussion about implementation in UnqualifiedId + /// From C++ [expr.prim.id.qual] + /// nested-name-specifier: + /// :: + /// type-name :: + /// namespace-name :: + /// decltype-specifier :: + /// nested-name-specifier identifier :: + /// nested-name-specifier template_opt simple-template-id :: + enum SpecifierKind { + Global, + TypeSpec, + Namespace, + DecltypeSpec, + Identifier, + TypeSpecWithTemplate + }; + +public: + NameSpecifier() : Tree(NodeKind::NameSpecifier) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::NameSpecifier; + } + SpecifierKind getKind(); + syntax::Leaf *getIdentifier(); + syntax::Leaf *getNamespaceName(); + //(...) + 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 a `operator-function-id`. C++ [over.oper] +/// operator-function-id: +/// 'operator' operator +/// operator: +/// + - * / = +/// (...) +class OperatorFunctionId final : public Tree { +public: + OperatorFunctionId() : Tree(NodeKind::OperatorFunctionId) {} + static bool classof(const Node *N) { + return N->kind() <= NodeKind::OperatorFunctionId; + } + syntax::Leaf *operatorKeyword(); + syntax::Leaf *operatorCode(); +}; + +/// 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 { + // The variants of `unqualified-id` - `identifier`, `operator-function-id`, + // ... - appear in other parts of the syntax. As such we want to implement + // them detached from `unqualified-id`. How to implement accessors to these + // variants? + // * Store an union with the variants and an enum of the kinds of + // variants. Access these variants by asking of what kind is + // `unqualified-id` and then using the appropriate getter. See: + // `UnqualifiedId` in "llvm-project/clang/include/clang/Sema/DeclSpec.h". + // * Similar but using std::variant instead of union. + // * not implement those accessors. +private: + enum class UnqualifiedIdKind { + IK_Identifier, + IK_OperatorFunctionId, + IK_ConversionFunctionId, + IK_LiteralOperatorId, + IK_DestructorName, + IK_TemplateId, + }; + +public: + UnqualifiedId() : Tree(NodeKind::UnqualifiedId) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::UnqualifiedId; + } + UnqualifiedIdKind getKind(); + syntax::Leaf *getIdentifier(); + 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 +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 + // * 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: