[clang] 7d382dc - [Syntax] Build declarator nodes
Dmitri Gribenko via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 16 11:22:37 PDT 2020
Author: Marcel Hlopko
Date: 2020-03-16T19:13:59+01:00
New Revision: 7d382dcd46a18c23a01e3754807f577598a9bc84
URL: https://github.com/llvm/llvm-project/commit/7d382dcd46a18c23a01e3754807f577598a9bc84
DIFF: https://github.com/llvm/llvm-project/commit/7d382dcd46a18c23a01e3754807f577598a9bc84.diff
LOG: [Syntax] Build declarator nodes
Summary:
Copy of https://reviews.llvm.org/D72089 with Ilya's permission. See
https://reviews.llvm.org/D72089 for the first batch of comments.
Reviewers: gribozavr2
Reviewed By: gribozavr2
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D76220
Added:
Modified:
clang/include/clang/Tooling/Syntax/Nodes.h
clang/lib/Tooling/Syntax/BuildTree.cpp
clang/lib/Tooling/Syntax/Nodes.cpp
clang/unittests/Tooling/Syntax/TreeTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h
index 25acc1757428..82fcac33f99b 100644
--- a/clang/include/clang/Tooling/Syntax/Nodes.h
+++ b/clang/include/clang/Tooling/Syntax/Nodes.h
@@ -38,10 +38,10 @@ enum class NodeKind : uint16_t {
Leaf,
TranslationUnit,
- // Expressions
+ // Expressions.
UnknownExpression,
- // Statements
+ // Statements.
UnknownStatement,
DeclarationStatement,
EmptyStatement,
@@ -58,7 +58,7 @@ enum class NodeKind : uint16_t {
ExpressionStatement,
CompoundStatement,
- // Declarations
+ // Declarations.
UnknownDeclaration,
EmptyDeclaration,
StaticAssertDeclaration,
@@ -68,7 +68,16 @@ enum class NodeKind : uint16_t {
NamespaceAliasDefinition,
UsingNamespaceDirective,
UsingDeclaration,
- TypeAliasDeclaration
+ TypeAliasDeclaration,
+
+ // Declarators.
+ SimpleDeclarator,
+ ParenDeclarator,
+
+ ArraySubscript,
+ TrailingReturnType,
+ ParametersAndQualifiers,
+ MemberPointer
};
/// For debugging purposes.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -101,11 +110,19 @@ enum class NodeRole : uint8_t {
ExpressionStatement_expression,
CompoundStatement_statement,
StaticAssertDeclaration_condition,
- StaticAssertDeclaration_message
+ StaticAssertDeclaration_message,
+ SimpleDeclaration_declarator,
+ ArraySubscript_sizeExpression,
+ TrailingReturnType_arrow,
+ TrailingReturnType_declarator,
+ ParametersAndQualifiers_parameter,
+ ParametersAndQualifiers_trailingReturn
};
/// For debugging purposes.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeRole R);
+class SimpleDeclarator;
+
/// A root node for a translation unit. Parent is always null.
class TranslationUnit final : public Tree {
public:
@@ -375,6 +392,8 @@ class SimpleDeclaration final : public Declaration {
static bool classof(const Node *N) {
return N->kind() == NodeKind::SimpleDeclaration;
}
+ /// FIXME: use custom iterator instead of 'vector'.
+ std::vector<syntax::SimpleDeclarator *> declarators();
};
/// namespace <name> { <decls> }
@@ -424,6 +443,113 @@ class TypeAliasDeclaration final : public Declaration {
}
};
+/// 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) {
+ return NodeKind::SimpleDeclarator <= N->kind() &&
+ N->kind() <= NodeKind::ParenDeclarator;
+ }
+};
+
+/// 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) {
+ return N->kind() == NodeKind::SimpleDeclarator;
+ }
+};
+
+/// 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) {
+ return N->kind() == NodeKind::ParenDeclarator;
+ }
+ syntax::Leaf *lparen();
+ syntax::Leaf *rparen();
+};
+
+/// 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) {
+ return N->kind() == NodeKind::ArraySubscript;
+ }
+ // TODO: add an accessor for the "static" keyword.
+ syntax::Leaf *lbracket();
+ syntax::Expression *sizeExpression();
+ syntax::Leaf *rbracket();
+};
+
+/// 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) {
+ return N->kind() == NodeKind::TrailingReturnType;
+ }
+ // TODO: add accessors for specifiers.
+ syntax::Leaf *arrow();
+ syntax::SimpleDeclarator *declarator();
+};
+
+/// 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) {
+ return N->kind() == NodeKind::ParametersAndQualifiers;
+ }
+ syntax::Leaf *lparen();
+ /// FIXME: use custom iterator instead of 'vector'.
+ std::vector<syntax::SimpleDeclaration *> parameters();
+ syntax::Leaf *rparen();
+ syntax::TrailingReturnType *trailingReturn();
+};
+
+/// 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) {
+ return N->kind() == NodeKind::MemberPointer;
+ }
+};
+
} // namespace syntax
} // namespace clang
#endif
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 243039413403..9ebf7d29d8ed 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -6,10 +6,15 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/AST/ASTFwd.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -20,6 +25,7 @@
#include "clang/Tooling/Syntax/Tree.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
@@ -34,6 +40,110 @@ using namespace clang;
LLVM_ATTRIBUTE_UNUSED
static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; }
+static SourceLocation getQualifiedNameStart(DeclaratorDecl *D) {
+ auto DN = D->getDeclName();
+ bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo();
+ if (IsAnonymous)
+ return SourceLocation();
+ return D->getQualifierLoc() ? D->getQualifierLoc().getBeginLoc()
+ : D->getLocation();
+}
+
+namespace {
+/// Get start location of the Declarator from the TypeLoc.
+/// E.g.:
+/// loc of `(` in `int (a)`
+/// loc of `*` in `int *(a)`
+/// loc of the first `(` in `int (*a)(int)`
+/// loc of the `*` in `int *(a)(int)`
+/// loc of the first `*` in `const int *const *volatile a;`
+///
+/// It is non-trivial to get the start location because TypeLocs are stored
+/// inside out. In the example above `*volatile` is the TypeLoc returned
+/// by `Decl.getTypeSourceInfo()`, and `*const` is what `.getPointeeLoc()`
+/// returns.
+struct GetStartLoc : TypeLocVisitor<GetStartLoc, SourceLocation> {
+ SourceLocation VisitParenTypeLoc(ParenTypeLoc T) {
+ auto L = Visit(T.getInnerLoc());
+ if (L.isValid())
+ return L;
+ return T.getLParenLoc();
+ }
+
+ // Types spelled in the prefix part of the declarator.
+ SourceLocation VisitPointerTypeLoc(PointerTypeLoc T) {
+ return HandlePointer(T);
+ }
+
+ SourceLocation VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
+ return HandlePointer(T);
+ }
+
+ SourceLocation VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
+ return HandlePointer(T);
+ }
+
+ SourceLocation VisitReferenceTypeLoc(ReferenceTypeLoc T) {
+ return HandlePointer(T);
+ }
+
+ SourceLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc T) {
+ return HandlePointer(T);
+ }
+
+ // All other cases are not important, as they are either part of declaration
+ // specifiers (e.g. inheritors of TypeSpecTypeLoc) or introduce modifiers on
+ // existing declarators (e.g. QualifiedTypeLoc). They cannot start the
+ // declarator themselves, but their underlying type can.
+ SourceLocation VisitTypeLoc(TypeLoc T) {
+ auto N = T.getNextTypeLoc();
+ if (!N)
+ return SourceLocation();
+ return Visit(N);
+ }
+
+ SourceLocation VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc T) {
+ if (T.getTypePtr()->hasTrailingReturn())
+ return SourceLocation(); // avoid recursing into the suffix of declarator.
+ return VisitTypeLoc(T);
+ }
+
+private:
+ template <class PtrLoc> SourceLocation HandlePointer(PtrLoc T) {
+ auto L = Visit(T.getPointeeLoc());
+ if (L.isValid())
+ return L;
+ return T.getLocalSourceRange().getBegin();
+ }
+};
+} // namespace
+
+/// Gets the range of declarator as defined by the C++ grammar. E.g.
+/// `int a;` -> range of `a`,
+/// `int *a;` -> range of `*a`,
+/// `int a[10];` -> range of `a[10]`,
+/// `int a[1][2][3];` -> range of `a[1][2][3]`,
+/// `int *a = nullptr` -> range of `*a = nullptr`.
+/// FIMXE: \p Name must be a source range, e.g. for `operator+`.
+static SourceRange getDeclaratorRange(const SourceManager &SM, TypeLoc T,
+ SourceLocation Name,
+ SourceRange Initializer) {
+ SourceLocation Start = GetStartLoc().Visit(T);
+ SourceLocation End = T.getSourceRange().getEnd();
+ assert(End.isValid());
+ if (Name.isValid()) {
+ if (Start.isInvalid())
+ Start = Name;
+ if (SM.isBeforeInTranslationUnit(End, Name))
+ End = Name;
+ }
+ if (Initializer.isValid()) {
+ assert(SM.isBeforeInTranslationUnit(End, Initializer.getEnd()));
+ End = Initializer.getEnd();
+ }
+ return SourceRange(Start, End);
+}
+
/// A helper class for constructing the syntax tree while traversing a clang
/// AST.
///
@@ -57,6 +167,7 @@ class syntax::TreeBuilder {
}
llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); }
+ const SourceManager &sourceManager() const { return Arena.sourceManager(); }
/// Populate children for \p New node, assuming it covers tokens from \p
/// Range.
@@ -64,16 +175,16 @@ class syntax::TreeBuilder {
/// Must be called with the range of each `DeclaratorDecl`. Ensures the
/// corresponding declarator nodes are covered by `SimpleDeclaration`.
- void noticeDeclaratorRange(llvm::ArrayRef<syntax::Token> Range);
+ void noticeDeclRange(llvm::ArrayRef<syntax::Token> Range);
/// Notifies that we should not consume trailing semicolon when computing
/// token range of \p D.
- void noticeDeclaratorWithoutSemicolon(Decl *D);
+ void noticeDeclWithoutSemicolon(Decl *D);
/// Mark the \p Child node with a corresponding \p Role. All marked children
/// should be consumed by foldNode.
- /// (!) when called on expressions (clang::Expr is derived from clang::Stmt),
- /// wraps expressions into expression statement.
+ /// When called on expressions (clang::Expr is derived from clang::Stmt),
+ /// wraps expressions into expression statement.
void markStmtChild(Stmt *Child, NodeRole Role);
/// Should be called for expressions in non-statement position to avoid
/// wrapping into expression statement.
@@ -81,6 +192,13 @@ class syntax::TreeBuilder {
/// Set role for a token starting at \p Loc.
void markChildToken(SourceLocation Loc, NodeRole R);
+ /// Set role for \p T.
+ void markChildToken(const syntax::Token *T, NodeRole R);
+
+ /// Set role for the node that spans exactly \p Range.
+ void markChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
+ /// Set role for the delayed node that spans exactly \p Range.
+ void markDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
/// Finish building the tree and consume the root node.
syntax::TranslationUnit *finalize() && {
@@ -141,7 +259,7 @@ class syntax::TreeBuilder {
withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const {
assert(!Tokens.empty());
assert(Tokens.back().kind() != tok::eof);
- // (!) we never consume 'eof', so looking at the next token is ok.
+ // We never consume 'eof', so looking at the next token is ok.
if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi)
return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1);
return Tokens;
@@ -172,6 +290,14 @@ class syntax::TreeBuilder {
~Forest() { assert(DelayedFolds.empty()); }
+ void assignRoleDelayed(llvm::ArrayRef<syntax::Token> Range,
+ syntax::NodeRole Role) {
+ auto It = DelayedFolds.find(Range.begin());
+ assert(It != DelayedFolds.end());
+ assert(It->second.End == Range.end());
+ It->second.Role = Role;
+ }
+
void assignRole(llvm::ArrayRef<syntax::Token> Range,
syntax::NodeRole Role) {
assert(!Range.empty());
@@ -189,12 +315,19 @@ class syntax::TreeBuilder {
llvm::ArrayRef<syntax::Token> Tokens,
syntax::Tree *Node) {
// Execute delayed folds inside `Tokens`.
- auto BeginExecuted = DelayedFolds.lower_bound(Tokens.begin());
- auto It = BeginExecuted;
- for (; It != DelayedFolds.end() && It->second.End <= Tokens.end(); ++It)
+ auto BeginFolds = DelayedFolds.lower_bound(Tokens.begin());
+ auto EndFolds = BeginFolds;
+ for (; EndFolds != DelayedFolds.end() &&
+ EndFolds->second.End <= Tokens.end();
+ ++EndFolds)
+ ;
+ // We go in reverse order to ensure we fold deeper nodes first.
+ for (auto RevIt = EndFolds; RevIt != BeginFolds; --RevIt) {
+ auto It = std::prev(RevIt);
foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End),
It->second.Node);
- DelayedFolds.erase(BeginExecuted, It);
+ }
+ DelayedFolds.erase(BeginFolds, EndFolds);
// Attach children to `Node`.
foldChildrenEager(A, Tokens, Node);
@@ -269,7 +402,7 @@ class syntax::TreeBuilder {
(EndChildren == Trees.end() || EndChildren->first == Tokens.end()) &&
"fold crosses boundaries of existing subtrees");
- // (!) we need to go in reverse order, because we can only prepend.
+ // We need to go in reverse order, because we can only prepend.
for (auto It = EndChildren; It != BeginChildren; --It)
Node->prependChildLowLevel(std::prev(It)->second.Node,
std::prev(It)->second.Role);
@@ -301,6 +434,7 @@ class syntax::TreeBuilder {
struct DelayedFold {
const syntax::Token *End = nullptr;
syntax::Tree *Node = nullptr;
+ NodeRole Role = NodeRole::Unknown;
};
std::map<const syntax::Token *, DelayedFold> DelayedFolds;
};
@@ -324,16 +458,43 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
bool shouldTraversePostOrder() const { return true; }
- bool WalkUpFromDeclaratorDecl(DeclaratorDecl *D) {
+ bool WalkUpFromDeclaratorDecl(DeclaratorDecl *DD) {
// Ensure declarators are covered by SimpleDeclaration.
- Builder.noticeDeclaratorRange(Builder.getRange(D));
- // FIXME: build nodes for the declarator too.
+ Builder.noticeDeclRange(Builder.getRange(DD));
+
+ // Build the declarator node.
+ SourceRange Initializer;
+ if (auto *V = llvm::dyn_cast<VarDecl>(DD)) {
+ auto *I = V->getInit();
+ // Initializers in range-based-for are not part of the declarator
+ if (I && !V->isCXXForRangeDecl())
+ Initializer = I->getSourceRange();
+ }
+ auto Declarator = getDeclaratorRange(
+ Builder.sourceManager(), DD->getTypeSourceInfo()->getTypeLoc(),
+ getQualifiedNameStart(DD), Initializer);
+ if (Declarator.isValid()) {
+ auto Tokens =
+ Builder.getRange(Declarator.getBegin(), Declarator.getEnd());
+ Builder.foldNode(Tokens, new (allocator()) syntax::SimpleDeclarator);
+ Builder.markChild(Tokens, syntax::NodeRole::SimpleDeclaration_declarator);
+ }
+
return true;
}
+
bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) {
- // Also a declarator.
- Builder.noticeDeclaratorRange(Builder.getRange(D));
- // FIXME: build nodes for the declarator too.
+ // Ensure declarators are covered by SimpleDeclaration.
+ Builder.noticeDeclRange(Builder.getRange(D));
+
+ auto R = getDeclaratorRange(
+ Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(),
+ /*Name=*/D->getLocation(), /*Initializer=*/SourceRange());
+ if (R.isValid()) {
+ auto Tokens = Builder.getRange(R.getBegin(), R.getEnd());
+ Builder.foldNode(Tokens, new (allocator()) syntax::SimpleDeclarator);
+ Builder.markChild(Tokens, syntax::NodeRole::SimpleDeclaration_declarator);
+ }
return true;
}
@@ -356,7 +517,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
}
bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) {
- // (!) we do not want to call VisitDecl(), the declaration for translation
+ // We do not want to call VisitDecl(), the declaration for translation
// unit is built by finalize().
return true;
}
@@ -401,10 +562,10 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) {
// We want to consume the semicolon, make sure SimpleDeclaration does not.
for (auto *D : DS->decls())
- Builder.noticeDeclaratorWithoutSemicolon(D);
+ Builder.noticeDeclWithoutSemicolon(D);
} else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) {
- // (!) do not recurse into subexpressions.
- // we do not have syntax trees for expressions yet, so we only want to see
+ // Do not recurse into subexpressions.
+ // We do not have syntax trees for expressions yet, so we only want to see
// the first top-level expression.
return WalkUpFromExpr(E->IgnoreImplicit());
}
@@ -431,6 +592,62 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
return true;
}
+ bool TraverseParenTypeLoc(ParenTypeLoc L) {
+ // We reverse order of traversal to get the proper syntax structure.
+ if (!WalkUpFromParenTypeLoc(L))
+ return false;
+ return TraverseTypeLoc(L.getInnerLoc());
+ }
+
+ bool WalkUpFromParenTypeLoc(ParenTypeLoc L) {
+ Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen);
+ Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen);
+ Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getRParenLoc()),
+ new (allocator()) syntax::ParenDeclarator);
+ return true;
+ }
+
+ // Declarator chunks, they are produced by type locs and some clang::Decls.
+ bool WalkUpFromArrayTypeLoc(ArrayTypeLoc L) {
+ Builder.markChildToken(L.getLBracketLoc(), syntax::NodeRole::OpenParen);
+ Builder.markExprChild(L.getSizeExpr(),
+ syntax::NodeRole::ArraySubscript_sizeExpression);
+ Builder.markChildToken(L.getRBracketLoc(), syntax::NodeRole::CloseParen);
+ Builder.foldNode(Builder.getRange(L.getLBracketLoc(), L.getRBracketLoc()),
+ new (allocator()) syntax::ArraySubscript);
+ return true;
+ }
+
+ bool WalkUpFromFunctionTypeLoc(FunctionTypeLoc L) {
+ Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen);
+ for (auto *P : L.getParams())
+ Builder.markDelayedChild(
+ Builder.getRange(P),
+ syntax::NodeRole::ParametersAndQualifiers_parameter);
+ Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen);
+ Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()),
+ new (allocator()) syntax::ParametersAndQualifiers);
+ return true;
+ }
+
+ bool WalkUpFromFunctionProtoTypeLoc(FunctionProtoTypeLoc L) {
+ if (!L.getTypePtr()->hasTrailingReturn())
+ return WalkUpFromFunctionTypeLoc(L);
+
+ auto TrailingReturnTokens = BuildTrailingReturn(L);
+ // Finish building the node for parameters.
+ Builder.markChild(TrailingReturnTokens,
+ syntax::NodeRole::ParametersAndQualifiers_trailingReturn);
+ return WalkUpFromFunctionTypeLoc(L);
+ }
+
+ bool WalkUpFromMemberPointerTypeLoc(MemberPointerTypeLoc L) {
+ auto SR = L.getLocalSourceRange();
+ Builder.foldNode(Builder.getRange(SR.getBegin(), SR.getEnd()),
+ new (allocator()) syntax::MemberPointer);
+ return true;
+ }
+
// The code below is very regular, it could even be generated with some
// preprocessor magic. We merely assign roles to the corresponding children
// and fold resulting nodes.
@@ -597,6 +814,37 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
}
private:
+ /// Returns the range of the built node.
+ llvm::ArrayRef<syntax::Token> BuildTrailingReturn(FunctionProtoTypeLoc L) {
+ assert(L.getTypePtr()->hasTrailingReturn());
+
+ auto ReturnedType = L.getReturnLoc();
+ // Build node for the declarator, if any.
+ auto ReturnDeclaratorRange =
+ getDeclaratorRange(this->Builder.sourceManager(), ReturnedType,
+ /*Name=*/SourceLocation(),
+ /*Initializer=*/SourceLocation());
+ llvm::ArrayRef<syntax::Token> ReturnDeclaratorTokens;
+ if (ReturnDeclaratorRange.isValid()) {
+ ReturnDeclaratorTokens = Builder.getRange(
+ ReturnDeclaratorRange.getBegin(), ReturnDeclaratorRange.getEnd());
+ Builder.foldNode(ReturnDeclaratorTokens,
+ new (allocator()) syntax::SimpleDeclarator);
+ }
+
+ // Build node for trailing return type.
+ auto Return =
+ Builder.getRange(ReturnedType.getBeginLoc(), ReturnedType.getEndLoc());
+ const auto *Arrow = Return.begin() - 1;
+ assert(Arrow->kind() == tok::arrow);
+ auto Tokens = llvm::makeArrayRef(Arrow, Return.end());
+ Builder.markChildToken(Arrow, syntax::NodeRole::TrailingReturnType_arrow);
+ if (!ReturnDeclaratorTokens.empty())
+ Builder.markChild(ReturnDeclaratorTokens,
+ syntax::NodeRole::TrailingReturnType_declarator);
+ Builder.foldNode(Tokens, new (allocator()) syntax::TrailingReturnType);
+ return Tokens;
+ }
/// A small helper to save some typing.
llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); }
@@ -610,15 +858,14 @@ void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range,
Pending.foldChildren(Arena, Range, New);
}
-void syntax::TreeBuilder::noticeDeclaratorRange(
- llvm::ArrayRef<syntax::Token> Range) {
+void syntax::TreeBuilder::noticeDeclRange(llvm::ArrayRef<syntax::Token> Range) {
if (Pending.extendDelayedFold(Range))
return;
Pending.foldChildrenDelayed(Range,
new (allocator()) syntax::SimpleDeclaration);
}
-void syntax::TreeBuilder::noticeDeclaratorWithoutSemicolon(Decl *D) {
+void syntax::TreeBuilder::noticeDeclWithoutSemicolon(Decl *D) {
DeclsWithoutSemicolons.insert(D);
}
@@ -628,6 +875,22 @@ void syntax::TreeBuilder::markChildToken(SourceLocation Loc, NodeRole Role) {
Pending.assignRole(*findToken(Loc), Role);
}
+void syntax::TreeBuilder::markChildToken(const syntax::Token *T, NodeRole R) {
+ if (!T)
+ return;
+ Pending.assignRole(*T, R);
+}
+
+void syntax::TreeBuilder::markChild(llvm::ArrayRef<syntax::Token> Range,
+ NodeRole R) {
+ Pending.assignRole(Range, R);
+}
+
+void syntax::TreeBuilder::markDelayedChild(llvm::ArrayRef<syntax::Token> Range,
+ NodeRole R) {
+ Pending.assignRoleDelayed(Range, R);
+}
+
void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
if (!Child)
return;
@@ -638,7 +901,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
if (auto *E = dyn_cast<Expr>(Child)) {
Pending.assignRole(getExprRange(E),
NodeRole::ExpressionStatement_expression);
- // (!) 'getRange(Stmt)' ensures this already covers a trailing semicolon.
+ // 'getRange(Stmt)' ensures this already covers a trailing semicolon.
Pending.foldChildren(Arena, Range,
new (allocator()) syntax::ExpressionStatement);
}
diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp
index 5b0c5107c134..4f86007e39bb 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -68,6 +68,18 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
return OS << "UsingDeclaration";
case NodeKind::TypeAliasDeclaration:
return OS << "TypeAliasDeclaration";
+ case NodeKind::SimpleDeclarator:
+ return OS << "SimpleDeclarator";
+ case NodeKind::ParenDeclarator:
+ return OS << "ParenDeclarator";
+ case NodeKind::ArraySubscript:
+ return OS << "ArraySubscript";
+ case NodeKind::TrailingReturnType:
+ return OS << "TrailingReturnType";
+ case NodeKind::ParametersAndQualifiers:
+ return OS << "ParametersAndQualifiers";
+ case NodeKind::MemberPointer:
+ return OS << "MemberPointer";
}
llvm_unreachable("unknown node kind");
}
@@ -104,6 +116,18 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
return OS << "StaticAssertDeclaration_condition";
case syntax::NodeRole::StaticAssertDeclaration_message:
return OS << "StaticAssertDeclaration_message";
+ case syntax::NodeRole::SimpleDeclaration_declarator:
+ return OS << "SimpleDeclaration_declarator";
+ case syntax::NodeRole::ArraySubscript_sizeExpression:
+ return OS << "ArraySubscript_sizeExpression";
+ case syntax::NodeRole::TrailingReturnType_arrow:
+ return OS << "TrailingReturnType_arrow";
+ case syntax::NodeRole::TrailingReturnType_declarator:
+ return OS << "TrailingReturnType_declarator";
+ case syntax::NodeRole::ParametersAndQualifiers_parameter:
+ return OS << "ParametersAndQualifiers_parameter";
+ case syntax::NodeRole::ParametersAndQualifiers_trailingReturn:
+ return OS << "ParametersAndQualifiers_trailingReturn";
}
llvm_unreachable("invalid role");
}
@@ -246,3 +270,73 @@ syntax::Expression *syntax::StaticAssertDeclaration::message() {
return llvm::cast_or_null<syntax::Expression>(
findChild(syntax::NodeRole::StaticAssertDeclaration_message));
}
+
+std::vector<syntax::SimpleDeclarator *>
+syntax::SimpleDeclaration::declarators() {
+ std::vector<syntax::SimpleDeclarator *> Children;
+ for (auto *C = firstChild(); C; C = C->nextSibling()) {
+ if (C->role() == syntax::NodeRole::SimpleDeclaration_declarator)
+ Children.push_back(llvm::cast<syntax::SimpleDeclarator>(C));
+ }
+ return Children;
+}
+
+syntax::Leaf *syntax::ParenDeclarator::lparen() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::OpenParen));
+}
+
+syntax::Leaf *syntax::ParenDeclarator::rparen() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::Leaf *syntax::ArraySubscript::lbracket() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::OpenParen));
+}
+
+syntax::Expression *syntax::ArraySubscript::sizeExpression() {
+ return llvm::cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::ArraySubscript_sizeExpression));
+}
+
+syntax::Leaf *syntax::ArraySubscript::rbracket() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::Leaf *syntax::TrailingReturnType::arrow() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::TrailingReturnType_arrow));
+}
+
+syntax::SimpleDeclarator *syntax::TrailingReturnType::declarator() {
+ return llvm::cast_or_null<syntax::SimpleDeclarator>(
+ findChild(syntax::NodeRole::TrailingReturnType_declarator));
+}
+
+syntax::Leaf *syntax::ParametersAndQualifiers::lparen() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::OpenParen));
+}
+
+std::vector<syntax::SimpleDeclaration *>
+syntax::ParametersAndQualifiers::parameters() {
+ std::vector<syntax::SimpleDeclaration *> Children;
+ for (auto *C = firstChild(); C; C = C->nextSibling()) {
+ if (C->role() == syntax::NodeRole::ParametersAndQualifiers_parameter)
+ Children.push_back(llvm::cast<syntax::SimpleDeclaration>(C));
+ }
+ return Children;
+}
+
+syntax::Leaf *syntax::ParametersAndQualifiers::rparen() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::TrailingReturnType *syntax::ParametersAndQualifiers::trailingReturn() {
+ return llvm::cast_or_null<syntax::TrailingReturnType>(
+ findChild(syntax::NodeRole::ParametersAndQualifiers_trailingReturn));
+}
diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp
index 1749e6635a12..6e914b6378c8 100644
--- a/clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -174,17 +174,21 @@ void foo() {}
*: TranslationUnit
|-SimpleDeclaration
| |-int
-| |-main
-| |-(
-| |-)
+| |-SimpleDeclarator
+| | |-main
+| | `-ParametersAndQualifiers
+| | |-(
+| | `-)
| `-CompoundStatement
| |-{
| `-}
`-SimpleDeclaration
|-void
- |-foo
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-foo
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
`-}
@@ -201,9 +205,11 @@ int main() {
*: TranslationUnit
`-SimpleDeclaration
|-int
- |-main
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-main
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-IfStatement
@@ -246,9 +252,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-ForStatement
@@ -268,18 +276,21 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-DeclarationStatement
| |-SimpleDeclaration
| | |-int
- | | |-a
- | | |-=
- | | `-UnknownExpression
- | | `-10
+ | | `-SimpleDeclarator
+ | | |-a
+ | | |-=
+ | | `-UnknownExpression
+ | | `-10
| `-;
`-}
)txt"},
@@ -287,9 +298,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-EmptyStatement
@@ -309,9 +322,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-SwitchStatement
@@ -345,9 +360,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-WhileStatement
@@ -375,9 +392,11 @@ int test() { return 1; }
*: TranslationUnit
`-SimpleDeclaration
|-int
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-ReturnStatement
@@ -398,26 +417,31 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-DeclarationStatement
| |-SimpleDeclaration
| | |-int
- | | |-a
- | | |-[
- | | |-UnknownExpression
- | | | `-3
- | | `-]
+ | | `-SimpleDeclarator
+ | | |-a
+ | | `-ArraySubscript
+ | | |-[
+ | | |-UnknownExpression
+ | | | `-3
+ | | `-]
| `-;
|-RangeBasedForStatement
| |-for
| |-(
| |-SimpleDeclaration
| | |-int
- | | |-x
+ | | |-SimpleDeclarator
+ | | | `-x
| | `-:
| |-UnknownExpression
| | `-a
@@ -433,9 +457,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-main
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-main
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-UnknownStatement
@@ -460,9 +486,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-ExpressionStatement
@@ -500,10 +528,12 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-int
- |-*
- |-a
+ |-SimpleDeclarator
+ | |-*
+ | `-a
|-,
- |-b
+ |-SimpleDeclarator
+ | `-b
`-;
)txt"},
{R"cpp(
@@ -514,10 +544,12 @@ void test() {
`-SimpleDeclaration
|-typedef
|-int
- |-*
- |-a
+ |-SimpleDeclarator
+ | |-*
+ | `-a
|-,
- |-b
+ |-SimpleDeclarator
+ | `-b
`-;
)txt"},
// Multiple declarators inside a statement.
@@ -531,27 +563,33 @@ void foo() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-foo
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-foo
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-DeclarationStatement
| |-SimpleDeclaration
| | |-int
- | | |-*
- | | |-a
+ | | |-SimpleDeclarator
+ | | | |-*
+ | | | `-a
| | |-,
- | | `-b
+ | | `-SimpleDeclarator
+ | | `-b
| `-;
|-DeclarationStatement
| |-SimpleDeclaration
| | |-typedef
| | |-int
- | | |-*
- | | |-ta
+ | | |-SimpleDeclarator
+ | | | |-*
+ | | | `-ta
| | |-,
- | | `-tb
+ | | `-SimpleDeclarator
+ | | `-tb
| `-;
`-}
)txt"},
@@ -617,23 +655,26 @@ struct {} *a1;
|-SimpleDeclaration
| |-struct
| |-Y
-| |-*
-| |-y1
+| |-SimpleDeclarator
+| | |-*
+| | `-y1
| `-;
|-SimpleDeclaration
| |-struct
| |-Y
| |-{
| |-}
-| |-*
-| |-y2
+| |-SimpleDeclarator
+| | |-*
+| | `-y2
| `-;
`-SimpleDeclaration
|-struct
|-{
|-}
- |-*
- |-a1
+ |-SimpleDeclarator
+ | |-*
+ | `-a1
`-;
)txt"},
{R"cpp(
@@ -666,7 +707,8 @@ using ns::a;
| |-{
| |-SimpleDeclaration
| | |-int
-| | |-a
+| | |-SimpleDeclarator
+| | | `-a
| | `-;
| `-}
`-UsingDeclaration
@@ -766,7 +808,8 @@ extern "C" { int b; int c; }
| |-"C"
| `-SimpleDeclaration
| |-int
-| |-a
+| |-SimpleDeclarator
+| | `-a
| `-;
`-LinkageSpecificationDeclaration
|-extern
@@ -774,11 +817,13 @@ extern "C" { int b; int c; }
|-{
|-SimpleDeclaration
| |-int
- | |-b
+ | |-SimpleDeclarator
+ | | `-b
| `-;
|-SimpleDeclaration
| |-int
- | |-c
+ | |-SimpleDeclarator
+ | | `-c
| `-;
`-}
)txt"},
@@ -793,9 +838,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-IfStatement
@@ -834,9 +881,11 @@ void test() {
*: TranslationUnit
`-SimpleDeclaration
|-void
- |-test
- |-(
- |-)
+ |-SimpleDeclarator
+ | |-test
+ | `-ParametersAndQualifiers
+ | |-(
+ | `-)
`-CompoundStatement
|-{
|-CompoundStatement
@@ -855,6 +904,533 @@ void test() {
| `-}
`-}
)txt"},
+ // Array subscripts in declarators.
+ {R"cpp(
+int a[10];
+int b[1][2][3];
+int c[] = {1,2,3};
+void f(int xs[static 10]);
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-a
+| | `-ArraySubscript
+| | |-[
+| | |-UnknownExpression
+| | | `-10
+| | `-]
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-b
+| | |-ArraySubscript
+| | | |-[
+| | | |-UnknownExpression
+| | | | `-1
+| | | `-]
+| | |-ArraySubscript
+| | | |-[
+| | | |-UnknownExpression
+| | | | `-2
+| | | `-]
+| | `-ArraySubscript
+| | |-[
+| | |-UnknownExpression
+| | | `-3
+| | `-]
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-c
+| | |-ArraySubscript
+| | | |-[
+| | | `-]
+| | |-=
+| | `-UnknownExpression
+| | |-{
+| | |-1
+| | |-,
+| | |-2
+| | |-,
+| | |-3
+| | `-}
+| `-;
+`-SimpleDeclaration
+ |-void
+ |-SimpleDeclarator
+ | |-f
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-SimpleDeclaration
+ | | |-int
+ | | `-SimpleDeclarator
+ | | |-xs
+ | | `-ArraySubscript
+ | | |-[
+ | | |-static
+ | | |-UnknownExpression
+ | | | `-10
+ | | `-]
+ | `-)
+ `-;
+ )txt"},
+ // Parameter lists in declarators.
+ {R"cpp(
+int a() const;
+int b() volatile;
+int c() &;
+int d() &&;
+int foo(int a, int b);
+int foo(
+ const int a,
+ volatile int b,
+ const volatile int c,
+ int* d,
+ int& e,
+ int&& f
+);
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-a
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-)
+| | `-const
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-b
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-)
+| | `-volatile
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-c
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-)
+| | `-&
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-d
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-)
+| | `-&&
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-foo
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-SimpleDeclaration
+| | | |-int
+| | | `-SimpleDeclarator
+| | | `-a
+| | |-,
+| | |-SimpleDeclaration
+| | | |-int
+| | | `-SimpleDeclarator
+| | | `-b
+| | `-)
+| `-;
+`-SimpleDeclaration
+ |-int
+ |-SimpleDeclarator
+ | |-foo
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-SimpleDeclaration
+ | | |-const
+ | | |-int
+ | | `-SimpleDeclarator
+ | | `-a
+ | |-,
+ | |-SimpleDeclaration
+ | | |-volatile
+ | | |-int
+ | | `-SimpleDeclarator
+ | | `-b
+ | |-,
+ | |-SimpleDeclaration
+ | | |-const
+ | | |-volatile
+ | | |-int
+ | | `-SimpleDeclarator
+ | | `-c
+ | |-,
+ | |-SimpleDeclaration
+ | | |-int
+ | | `-SimpleDeclarator
+ | | |-*
+ | | `-d
+ | |-,
+ | |-SimpleDeclaration
+ | | |-int
+ | | `-SimpleDeclarator
+ | | |-&
+ | | `-e
+ | |-,
+ | |-SimpleDeclaration
+ | | |-int
+ | | `-SimpleDeclarator
+ | | |-&&
+ | | `-f
+ | `-)
+ `-;
+ )txt"},
+ // Trailing const qualifier.
+ {R"cpp(
+struct X {
+ int foo() const;
+}
+ )cpp",
+ R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+ |-struct
+ |-X
+ |-{
+ |-SimpleDeclaration
+ | |-int
+ | |-SimpleDeclarator
+ | | |-foo
+ | | `-ParametersAndQualifiers
+ | | |-(
+ | | |-)
+ | | `-const
+ | `-;
+ `-}
+ )txt"},
+ // Trailing return type in parameter lists.
+ {R"cpp(
+auto foo() -> int;
+ )cpp",
+ R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+ |-auto
+ |-SimpleDeclarator
+ | |-foo
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-)
+ | `-TrailingReturnType
+ | |-->
+ | `-int
+ `-;
+ )txt"},
+ // Exception specification in parameter lists.
+ {R"cpp(
+int a() noexcept;
+int b() noexcept(true);
+int c() throw();
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-a
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-)
+| | `-noexcept
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-b
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-)
+| | |-noexcept
+| | |-(
+| | |-UnknownExpression
+| | | `-true
+| | `-)
+| `-;
+`-SimpleDeclaration
+ |-int
+ |-SimpleDeclarator
+ | |-c
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-)
+ | |-throw
+ | |-(
+ | `-)
+ `-;
+ )txt"},
+ // Declarators in parentheses.
+ {R"cpp(
+int (a);
+int *(b);
+int (*c)(int);
+int *(d)(int);
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | `-ParenDeclarator
+| | |-(
+| | |-a
+| | `-)
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-*
+| | `-ParenDeclarator
+| | |-(
+| | |-b
+| | `-)
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-ParenDeclarator
+| | | |-(
+| | | |-*
+| | | |-c
+| | | `-)
+| | `-ParametersAndQualifiers
+| | |-(
+| | |-SimpleDeclaration
+| | | `-int
+| | `-)
+| `-;
+`-SimpleDeclaration
+ |-int
+ |-SimpleDeclarator
+ | |-*
+ | |-ParenDeclarator
+ | | |-(
+ | | |-d
+ | | `-)
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-SimpleDeclaration
+ | | `-int
+ | `-)
+ `-;
+ )txt"},
+ // CV qualifiers.
+ {R"cpp(
+const int west = -1;
+int const east = 1;
+const int const universal = 0;
+const int const *const *volatile b;
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-const
+| |-int
+| |-SimpleDeclarator
+| | |-west
+| | |-=
+| | `-UnknownExpression
+| | |--
+| | `-1
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-const
+| |-SimpleDeclarator
+| | |-east
+| | |-=
+| | `-UnknownExpression
+| | `-1
+| `-;
+|-SimpleDeclaration
+| |-const
+| |-int
+| |-const
+| |-SimpleDeclarator
+| | |-universal
+| | |-=
+| | `-UnknownExpression
+| | `-0
+| `-;
+`-SimpleDeclaration
+ |-const
+ |-int
+ |-const
+ |-SimpleDeclarator
+ | |-*
+ | |-const
+ | |-*
+ | |-volatile
+ | `-b
+ `-;
+ )txt"},
+ // Ranges of declarators with trailing return types.
+ {R"cpp(
+auto foo() -> auto(*)(int) -> double*;
+ )cpp",
+ R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+ |-auto
+ |-SimpleDeclarator
+ | |-foo
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-)
+ | `-TrailingReturnType
+ | |-->
+ | |-auto
+ | `-SimpleDeclarator
+ | |-ParenDeclarator
+ | | |-(
+ | | |-*
+ | | `-)
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-SimpleDeclaration
+ | | `-int
+ | |-)
+ | `-TrailingReturnType
+ | |-->
+ | |-double
+ | `-SimpleDeclarator
+ | `-*
+ `-;
+ )txt"},
+ // Member pointers.
+ {R"cpp(
+struct X {};
+int X::* a;
+const int X::* b;
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-struct
+| |-X
+| |-{
+| |-}
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-MemberPointer
+| | | |-X
+| | | |-::
+| | | `-*
+| | `-a
+| `-;
+`-SimpleDeclaration
+ |-const
+ |-int
+ |-SimpleDeclarator
+ | |-MemberPointer
+ | | |-X
+ | | |-::
+ | | `-*
+ | `-b
+ `-;
+ )txt"},
+ // All-in-one tests.
+ {R"cpp(
+void x(char a, short (*b)(int));
+ )cpp",
+ R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+ |-void
+ |-SimpleDeclarator
+ | |-x
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-SimpleDeclaration
+ | | |-char
+ | | `-SimpleDeclarator
+ | | `-a
+ | |-,
+ | |-SimpleDeclaration
+ | | |-short
+ | | `-SimpleDeclarator
+ | | |-ParenDeclarator
+ | | | |-(
+ | | | |-*
+ | | | |-b
+ | | | `-)
+ | | `-ParametersAndQualifiers
+ | | |-(
+ | | |-SimpleDeclaration
+ | | | `-int
+ | | `-)
+ | `-)
+ `-;
+ )txt"},
+ {R"cpp(
+void x(char a, short (*b)(int), long (**c)(long long));
+ )cpp",
+ R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+ |-void
+ |-SimpleDeclarator
+ | |-x
+ | `-ParametersAndQualifiers
+ | |-(
+ | |-SimpleDeclaration
+ | | |-char
+ | | `-SimpleDeclarator
+ | | `-a
+ | |-,
+ | |-SimpleDeclaration
+ | | |-short
+ | | `-SimpleDeclarator
+ | | |-ParenDeclarator
+ | | | |-(
+ | | | |-*
+ | | | |-b
+ | | | `-)
+ | | `-ParametersAndQualifiers
+ | | |-(
+ | | |-SimpleDeclaration
+ | | | `-int
+ | | `-)
+ | |-,
+ | |-SimpleDeclaration
+ | | |-long
+ | | `-SimpleDeclarator
+ | | |-ParenDeclarator
+ | | | |-(
+ | | | |-*
+ | | | |-*
+ | | | |-c
+ | | | `-)
+ | | `-ParametersAndQualifiers
+ | | |-(
+ | | |-SimpleDeclaration
+ | | | |-long
+ | | | `-long
+ | | `-)
+ | `-)
+ `-;
+ )txt"},
};
for (const auto &T : Cases) {
More information about the cfe-commits
mailing list