summaryrefslogtreecommitdiff
path: root/clang/lib/Tooling/Syntax
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
commitb60736ec1405bb0a8dd40989f67ef4c93da068ab (patch)
tree5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /clang/lib/Tooling/Syntax
parentcfca06d7963fa0909f90483b42a6d7d194d01e08 (diff)
Diffstat (limited to 'clang/lib/Tooling/Syntax')
-rw-r--r--clang/lib/Tooling/Syntax/BuildTree.cpp817
-rw-r--r--clang/lib/Tooling/Syntax/ComputeReplacements.cpp15
-rw-r--r--clang/lib/Tooling/Syntax/Mutations.cpp36
-rw-r--r--clang/lib/Tooling/Syntax/Nodes.cpp604
-rw-r--r--clang/lib/Tooling/Syntax/Synthesis.cpp224
-rw-r--r--clang/lib/Tooling/Syntax/Tokens.cpp89
-rw-r--r--clang/lib/Tooling/Syntax/Tree.cpp410
7 files changed, 1440 insertions, 755 deletions
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 1f192180ec45..7654e3dfaa01 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -13,6 +13,8 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/IgnoreExpr.h"
+#include "clang/AST/OperationKinds.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TypeLoc.h"
@@ -44,8 +46,44 @@
using namespace clang;
+// Ignores the implicit `CXXConstructExpr` for copy/move constructor calls
+// generated by the compiler, as well as in implicit conversions like the one
+// wrapping `1` in `X x = 1;`.
+static Expr *IgnoreImplicitConstructorSingleStep(Expr *E) {
+ if (auto *C = dyn_cast<CXXConstructExpr>(E)) {
+ auto NumArgs = C->getNumArgs();
+ if (NumArgs == 1 || (NumArgs > 1 && isa<CXXDefaultArgExpr>(C->getArg(1)))) {
+ Expr *A = C->getArg(0);
+ if (C->getParenOrBraceRange().isInvalid())
+ return A;
+ }
+ }
+ return E;
+}
+
+// In:
+// struct X {
+// X(int)
+// };
+// X x = X(1);
+// Ignores the implicit `CXXFunctionalCastExpr` that wraps
+// `CXXConstructExpr X(1)`.
+static Expr *IgnoreCXXFunctionalCastExprWrappingConstructor(Expr *E) {
+ if (auto *F = dyn_cast<CXXFunctionalCastExpr>(E)) {
+ if (F->getCastKind() == CK_ConstructorConversion)
+ return F->getSubExpr();
+ }
+ return E;
+}
+
+static Expr *IgnoreImplicit(Expr *E) {
+ return IgnoreExprNodes(E, IgnoreImplicitSingleStep,
+ IgnoreImplicitConstructorSingleStep,
+ IgnoreCXXFunctionalCastExprWrappingConstructor);
+}
+
LLVM_ATTRIBUTE_UNUSED
-static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; }
+static bool isImplicitExpr(Expr *E) { return IgnoreImplicit(E) != E; }
namespace {
/// Get start location of the Declarator from the TypeLoc.
@@ -116,6 +154,13 @@ private:
};
} // namespace
+static CallExpr::arg_range dropDefaultArgs(CallExpr::arg_range Args) {
+ auto FirstDefaultArg = std::find_if(Args.begin(), Args.end(), [](auto It) {
+ return isa<CXXDefaultArgExpr>(It);
+ });
+ return llvm::make_range(Args.begin(), FirstDefaultArg);
+}
+
static syntax::NodeKind getOperatorNodeKind(const CXXOperatorCallExpr &E) {
switch (E.getOperator()) {
// Comparison
@@ -184,10 +229,11 @@ static syntax::NodeKind getOperatorNodeKind(const CXXOperatorCallExpr &E) {
case OO_Array_New:
case OO_Array_Delete:
case OO_Coawait:
- case OO_Call:
case OO_Subscript:
case OO_Arrow:
return syntax::NodeKind::UnknownExpression;
+ case OO_Call:
+ return syntax::NodeKind::CallExpression;
case OO_Conditional: // not overloadable
case NUM_OVERLOADED_OPERATORS:
case OO_None:
@@ -196,18 +242,58 @@ static syntax::NodeKind getOperatorNodeKind(const CXXOperatorCallExpr &E) {
llvm_unreachable("Unknown OverloadedOperatorKind enum");
}
+/// Get the start of the qualified name. In the examples below it gives the
+/// location of the `^`:
+/// `int ^a;`
+/// `int *^a;`
+/// `int ^a::S::f(){}`
+static SourceLocation getQualifiedNameStart(NamedDecl *D) {
+ assert((isa<DeclaratorDecl, TypedefNameDecl>(D)) &&
+ "only DeclaratorDecl and TypedefNameDecl are supported.");
+
+ auto DN = D->getDeclName();
+ bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo();
+ if (IsAnonymous)
+ return SourceLocation();
+
+ if (const auto *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (DD->getQualifierLoc()) {
+ return DD->getQualifierLoc().getBeginLoc();
+ }
+ }
+
+ return D->getLocation();
+}
+
+/// Gets the range of the initializer inside an init-declarator C++ [dcl.decl].
+/// `int a;` -> range of ``,
+/// `int *a = nullptr` -> range of `= nullptr`.
+/// `int a{}` -> range of `{}`.
+/// `int a()` -> range of `()`.
+static SourceRange getInitializerRange(Decl *D) {
+ if (auto *V = dyn_cast<VarDecl>(D)) {
+ auto *I = V->getInit();
+ // Initializers in range-based-for are not part of the declarator
+ if (I && !V->isCXXForRangeDecl())
+ return I->getSourceRange();
+ }
+
+ return SourceRange();
+}
+
/// 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+`.
+/// `int S::f(){}` -> range of `S::f()`.
+/// FIXME: \p Name must be a source range.
static SourceRange getDeclaratorRange(const SourceManager &SM, TypeLoc T,
SourceLocation Name,
SourceRange Initializer) {
SourceLocation Start = GetStartLoc().Visit(T);
- SourceLocation End = T.getSourceRange().getEnd();
+ SourceLocation End = T.getEndLoc();
assert(End.isValid());
if (Name.isValid()) {
if (Start.isInvalid())
@@ -241,10 +327,24 @@ public:
assert(Added && "mapping added twice");
}
+ void add(NestedNameSpecifierLoc From, syntax::Tree *To) {
+ assert(To != nullptr);
+ assert(From.hasQualifier());
+
+ bool Added = NNSNodes.insert({From, To}).second;
+ (void)Added;
+ assert(Added && "mapping added twice");
+ }
+
syntax::Tree *find(ASTPtr P) const { return Nodes.lookup(P); }
+ syntax::Tree *find(NestedNameSpecifierLoc P) const {
+ return NNSNodes.lookup(P);
+ }
+
private:
llvm::DenseMap<ASTPtr, syntax::Tree *> Nodes;
+ llvm::DenseMap<NestedNameSpecifierLoc, syntax::Tree *> NNSNodes;
};
} // namespace
@@ -266,28 +366,48 @@ private:
class syntax::TreeBuilder {
public:
TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {
- for (const auto &T : Arena.tokenBuffer().expandedTokens())
- LocationToToken.insert({T.location().getRawEncoding(), &T});
+ for (const auto &T : Arena.getTokenBuffer().expandedTokens())
+ LocationToToken.insert({T.location(), &T});
}
- llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); }
- const SourceManager &sourceManager() const { return Arena.sourceManager(); }
+ llvm::BumpPtrAllocator &allocator() { return Arena.getAllocator(); }
+ const SourceManager &sourceManager() const {
+ return Arena.getSourceManager();
+ }
/// Populate children for \p New node, assuming it covers tokens from \p
/// Range.
- void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New,
- ASTPtr From) {
+ void foldNode(ArrayRef<syntax::Token> Range, syntax::Tree *New, ASTPtr From) {
assert(New);
Pending.foldChildren(Arena, Range, New);
if (From)
Mapping.add(From, New);
}
- void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New,
- TypeLoc L) {
+
+ void foldNode(ArrayRef<syntax::Token> Range, syntax::Tree *New, TypeLoc L) {
// FIXME: add mapping for TypeLocs
foldNode(Range, New, nullptr);
}
+ void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New,
+ NestedNameSpecifierLoc From) {
+ assert(New);
+ Pending.foldChildren(Arena, Range, New);
+ if (From)
+ Mapping.add(From, New);
+ }
+
+ /// Populate children for \p New list, assuming it covers tokens from a
+ /// subrange of \p SuperRange.
+ void foldList(ArrayRef<syntax::Token> SuperRange, syntax::List *New,
+ ASTPtr From) {
+ assert(New);
+ auto ListRange = Pending.shrinkToFitList(SuperRange);
+ Pending.foldChildren(Arena, ListRange, New);
+ if (From)
+ Mapping.add(From, New);
+ }
+
/// Notifies that we should not consume trailing semicolon when computing
/// token range of \p D.
void noticeDeclWithoutSemicolon(Decl *D);
@@ -309,16 +429,18 @@ public:
void markChild(syntax::Node *N, NodeRole R);
/// Set role for the syntax node matching \p N.
void markChild(ASTPtr N, NodeRole R);
+ /// Set role for the syntax node matching \p N.
+ void markChild(NestedNameSpecifierLoc N, NodeRole R);
/// Finish building the tree and consume the root node.
syntax::TranslationUnit *finalize() && {
- auto Tokens = Arena.tokenBuffer().expandedTokens();
+ auto Tokens = Arena.getTokenBuffer().expandedTokens();
assert(!Tokens.empty());
assert(Tokens.back().kind() == tok::eof);
// Build the root of the tree, consuming all the children.
Pending.foldChildren(Arena, Tokens.drop_back(),
- new (Arena.allocator()) syntax::TranslationUnit);
+ new (Arena.getAllocator()) syntax::TranslationUnit);
auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize());
TU->assertInvariantsRecursive();
@@ -329,7 +451,7 @@ public:
const syntax::Token *findToken(SourceLocation L) const;
/// Finds the syntax tokens corresponding to the \p SourceRange.
- llvm::ArrayRef<syntax::Token> getRange(SourceRange Range) const {
+ ArrayRef<syntax::Token> getRange(SourceRange Range) const {
assert(Range.isValid());
return getRange(Range.getBegin(), Range.getEnd());
}
@@ -337,16 +459,16 @@ public:
/// Finds the syntax tokens corresponding to the passed source locations.
/// \p First is the start position of the first token and \p Last is the start
/// position of the last token.
- llvm::ArrayRef<syntax::Token> getRange(SourceLocation First,
- SourceLocation Last) const {
+ ArrayRef<syntax::Token> getRange(SourceLocation First,
+ SourceLocation Last) const {
assert(First.isValid());
assert(Last.isValid());
assert(First == Last ||
- Arena.sourceManager().isBeforeInTranslationUnit(First, Last));
+ Arena.getSourceManager().isBeforeInTranslationUnit(First, Last));
return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
}
- llvm::ArrayRef<syntax::Token>
+ ArrayRef<syntax::Token>
getTemplateRange(const ClassTemplateSpecializationDecl *D) const {
auto Tokens = getRange(D->getSourceRange());
return maybeAppendSemicolon(Tokens, D);
@@ -354,11 +476,9 @@ public:
/// Returns true if \p D is the last declarator in a chain and is thus
/// reponsible for creating SimpleDeclaration for the whole chain.
- template <class T>
- bool isResponsibleForCreatingDeclaration(const T *D) const {
- static_assert((std::is_base_of<DeclaratorDecl, T>::value ||
- std::is_base_of<TypedefNameDecl, T>::value),
- "only DeclaratorDecl and TypedefNameDecl are supported.");
+ bool isResponsibleForCreatingDeclaration(const Decl *D) const {
+ assert((isa<DeclaratorDecl, TypedefNameDecl>(D)) &&
+ "only DeclaratorDecl and TypedefNameDecl are supported.");
const Decl *Next = D->getNextDeclInContext();
@@ -366,15 +486,14 @@ public:
if (Next == nullptr) {
return true;
}
- const auto *NextT = llvm::dyn_cast<T>(Next);
// Next sibling is not the same type, this one is responsible.
- if (NextT == nullptr) {
+ if (D->getKind() != Next->getKind()) {
return true;
}
// Next sibling doesn't begin at the same loc, it must be a different
// declaration, so this declarator is responsible.
- if (NextT->getBeginLoc() != D->getBeginLoc()) {
+ if (Next->getBeginLoc() != D->getBeginLoc()) {
return true;
}
@@ -383,23 +502,23 @@ public:
return false;
}
- llvm::ArrayRef<syntax::Token> getDeclarationRange(Decl *D) {
- llvm::ArrayRef<clang::syntax::Token> Tokens;
+ ArrayRef<syntax::Token> getDeclarationRange(Decl *D) {
+ ArrayRef<syntax::Token> Tokens;
// We want to drop the template parameters for specializations.
- if (const auto *S = llvm::dyn_cast<TagDecl>(D))
+ if (const auto *S = dyn_cast<TagDecl>(D))
Tokens = getRange(S->TypeDecl::getBeginLoc(), S->getEndLoc());
else
Tokens = getRange(D->getSourceRange());
return maybeAppendSemicolon(Tokens, D);
}
- llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const {
+ ArrayRef<syntax::Token> getExprRange(const Expr *E) const {
return getRange(E->getSourceRange());
}
/// Find the adjusted range for the statement, consuming the trailing
/// semicolon when needed.
- llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const {
+ ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const {
auto Tokens = getRange(S->getSourceRange());
if (isa<CompoundStmt>(S))
return Tokens;
@@ -412,10 +531,9 @@ public:
}
private:
- llvm::ArrayRef<syntax::Token>
- maybeAppendSemicolon(llvm::ArrayRef<syntax::Token> Tokens,
- const Decl *D) const {
- if (llvm::isa<NamespaceDecl>(D))
+ ArrayRef<syntax::Token> maybeAppendSemicolon(ArrayRef<syntax::Token> Tokens,
+ const Decl *D) const {
+ if (isa<NamespaceDecl>(D))
return Tokens;
if (DeclsWithoutSemicolons.count(D))
return Tokens;
@@ -424,8 +542,8 @@ private:
return withTrailingSemicolon(Tokens);
}
- llvm::ArrayRef<syntax::Token>
- withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const {
+ ArrayRef<syntax::Token>
+ withTrailingSemicolon(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.
@@ -435,7 +553,7 @@ private:
}
void setRole(syntax::Node *N, NodeRole R) {
- assert(N->role() == NodeRole::Detached);
+ assert(N->getRole() == NodeRole::Detached);
N->setRole(R);
}
@@ -447,20 +565,19 @@ private:
/// Ensures that added nodes properly nest and cover the whole token stream.
struct Forest {
Forest(syntax::Arena &A) {
- assert(!A.tokenBuffer().expandedTokens().empty());
- assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof);
+ assert(!A.getTokenBuffer().expandedTokens().empty());
+ assert(A.getTokenBuffer().expandedTokens().back().kind() == tok::eof);
// Create all leaf nodes.
// Note that we do not have 'eof' in the tree.
- for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) {
- auto *L = new (A.allocator()) syntax::Leaf(&T);
+ for (const auto &T : A.getTokenBuffer().expandedTokens().drop_back()) {
+ auto *L = new (A.getAllocator()) syntax::Leaf(&T);
L->Original = true;
- L->CanModify = A.tokenBuffer().spelledForExpanded(T).hasValue();
+ L->CanModify = A.getTokenBuffer().spelledForExpanded(T).hasValue();
Trees.insert(Trees.end(), {&T, L});
}
}
- void assignRole(llvm::ArrayRef<syntax::Token> Range,
- syntax::NodeRole Role) {
+ void assignRole(ArrayRef<syntax::Token> Range, syntax::NodeRole Role) {
assert(!Range.empty());
auto It = Trees.lower_bound(Range.begin());
assert(It != Trees.end() && "no node found");
@@ -468,17 +585,45 @@ private:
assert((std::next(It) == Trees.end() ||
std::next(It)->first == Range.end()) &&
"no child with the specified range");
- assert(It->second->role() == NodeRole::Detached &&
+ assert(It->second->getRole() == NodeRole::Detached &&
"re-assigning role for a child");
It->second->setRole(Role);
}
+ /// Shrink \p Range to a subrange that only contains tokens of a list.
+ /// List elements and delimiters should already have correct roles.
+ ArrayRef<syntax::Token> shrinkToFitList(ArrayRef<syntax::Token> Range) {
+ auto BeginChildren = Trees.lower_bound(Range.begin());
+ assert((BeginChildren == Trees.end() ||
+ BeginChildren->first == Range.begin()) &&
+ "Range crosses boundaries of existing subtrees");
+
+ auto EndChildren = Trees.lower_bound(Range.end());
+ assert(
+ (EndChildren == Trees.end() || EndChildren->first == Range.end()) &&
+ "Range crosses boundaries of existing subtrees");
+
+ auto BelongsToList = [](decltype(Trees)::value_type KV) {
+ auto Role = KV.second->getRole();
+ return Role == syntax::NodeRole::ListElement ||
+ Role == syntax::NodeRole::ListDelimiter;
+ };
+
+ auto BeginListChildren =
+ std::find_if(BeginChildren, EndChildren, BelongsToList);
+
+ auto EndListChildren =
+ std::find_if_not(BeginListChildren, EndChildren, BelongsToList);
+
+ return ArrayRef<syntax::Token>(BeginListChildren->first,
+ EndListChildren->first);
+ }
+
/// Add \p Node to the forest and attach child nodes based on \p Tokens.
- void foldChildren(const syntax::Arena &A,
- llvm::ArrayRef<syntax::Token> Tokens,
+ void foldChildren(const syntax::Arena &A, ArrayRef<syntax::Token> Tokens,
syntax::Tree *Node) {
// Attach children to `Node`.
- assert(Node->firstChild() == nullptr && "node already has children");
+ assert(Node->getFirstChild() == nullptr && "node already has children");
auto *FirstToken = Tokens.begin();
auto BeginChildren = Trees.lower_bound(FirstToken);
@@ -491,17 +636,17 @@ private:
(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.
- for (auto It = EndChildren; It != BeginChildren; --It) {
- auto *C = std::prev(It)->second;
- if (C->role() == NodeRole::Detached)
+ for (auto It = BeginChildren; It != EndChildren; ++It) {
+ auto *C = It->second;
+ if (C->getRole() == NodeRole::Detached)
C->setRole(NodeRole::Unknown);
- Node->prependChildLowLevel(C);
+ Node->appendChildLowLevel(C);
}
// Mark that this node came from the AST and is backed by the source code.
Node->Original = true;
- Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue();
+ Node->CanModify =
+ A.getTokenBuffer().spelledForExpanded(Tokens).hasValue();
Trees.erase(BeginChildren, EndChildren);
Trees.insert({FirstToken, Node});
@@ -521,12 +666,12 @@ private:
unsigned CoveredTokens =
It != Trees.end()
? (std::next(It)->first - It->first)
- : A.tokenBuffer().expandedTokens().end() - It->first;
+ : A.getTokenBuffer().expandedTokens().end() - It->first;
- R += std::string(llvm::formatv(
- "- '{0}' covers '{1}'+{2} tokens\n", It->second->kind(),
- It->first->text(A.sourceManager()), CoveredTokens));
- R += It->second->dump(A);
+ R += std::string(
+ formatv("- '{0}' covers '{1}'+{2} tokens\n", It->second->getKind(),
+ It->first->text(A.getSourceManager()), CoveredTokens));
+ R += It->second->dump(A.getSourceManager());
}
return R;
}
@@ -543,8 +688,7 @@ private:
syntax::Arena &Arena;
/// To quickly find tokens by their start location.
- llvm::DenseMap</*SourceLocation*/ unsigned, const syntax::Token *>
- LocationToToken;
+ llvm::DenseMap<SourceLocation, const syntax::Token *> LocationToToken;
Forest Pending;
llvm::DenseSet<Decl *> DeclsWithoutSemicolons;
ASTToSyntaxMapping Mapping;
@@ -623,7 +767,7 @@ public:
foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
DeclarationRange = R;
};
- if (auto *S = llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
+ if (auto *S = dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
ConsumeTemplateParameters(*S->getTemplateParameters());
for (unsigned I = C->getNumTemplateParameterLists(); 0 < I; --I)
ConsumeTemplateParameters(*C->getTemplateParameterList(I - 1));
@@ -641,7 +785,7 @@ public:
Builder.markChildToken(S->getLBracLoc(), NodeRole::OpenParen);
for (auto *Child : S->body())
- Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement);
+ Builder.markStmtChild(Child, NodeRole::Statement);
Builder.markChildToken(S->getRBracLoc(), NodeRole::CloseParen);
Builder.foldNode(Builder.getStmtRange(S),
@@ -677,12 +821,12 @@ public:
}
bool TraverseStmt(Stmt *S) {
- if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) {
+ if (auto *DS = dyn_cast_or_null<DeclStmt>(S)) {
// We want to consume the semicolon, make sure SimpleDeclaration does not.
for (auto *D : DS->decls())
Builder.noticeDeclWithoutSemicolon(D);
- } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) {
- return RecursiveASTVisitor::TraverseStmt(E->IgnoreImplicit());
+ } else if (auto *E = dyn_cast_or_null<Expr>(S)) {
+ return RecursiveASTVisitor::TraverseStmt(IgnoreImplicit(E));
}
return RecursiveASTVisitor::TraverseStmt(S);
}
@@ -695,21 +839,6 @@ public:
return true;
}
- syntax::NestedNameSpecifier *
- BuildNestedNameSpecifier(NestedNameSpecifierLoc QualifierLoc) {
- if (!QualifierLoc)
- return nullptr;
- for (auto it = QualifierLoc; it; it = it.getPrefix()) {
- auto *NS = new (allocator()) syntax::NameSpecifier;
- Builder.foldNode(Builder.getRange(it.getLocalSourceRange()), NS, nullptr);
- Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier);
- }
- auto *NNS = new (allocator()) syntax::NestedNameSpecifier;
- Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), NNS,
- nullptr);
- return NNS;
- }
-
bool TraverseUserDefinedLiteral(UserDefinedLiteral *S) {
// The semantic AST node `UserDefinedLiteral` (UDL) may have one child node
// referencing the location of the UDL suffix (`_w` in `1.2_w`). The
@@ -722,16 +851,16 @@ public:
syntax::UserDefinedLiteralExpression *
buildUserDefinedLiteral(UserDefinedLiteral *S) {
switch (S->getLiteralOperatorKind()) {
- case clang::UserDefinedLiteral::LOK_Integer:
+ case UserDefinedLiteral::LOK_Integer:
return new (allocator()) syntax::IntegerUserDefinedLiteralExpression;
- case clang::UserDefinedLiteral::LOK_Floating:
+ case UserDefinedLiteral::LOK_Floating:
return new (allocator()) syntax::FloatUserDefinedLiteralExpression;
- case clang::UserDefinedLiteral::LOK_Character:
+ case UserDefinedLiteral::LOK_Character:
return new (allocator()) syntax::CharUserDefinedLiteralExpression;
- case clang::UserDefinedLiteral::LOK_String:
+ case UserDefinedLiteral::LOK_String:
return new (allocator()) syntax::StringUserDefinedLiteralExpression;
- case clang::UserDefinedLiteral::LOK_Raw:
- case clang::UserDefinedLiteral::LOK_Template:
+ case UserDefinedLiteral::LOK_Raw:
+ case UserDefinedLiteral::LOK_Template:
// For raw literal operator and numeric literal operator template we
// cannot get the type of the operand in the semantic AST. We get this
// information from the token. As integer and floating point have the same
@@ -759,34 +888,202 @@ public:
return true;
}
- bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
- if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
- Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
+ // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` for the
+ // `DependentTemplateSpecializationType` case.
+ /// Given a nested-name-specifier return the range for the last name
+ /// specifier.
+ ///
+ /// e.g. `std::T::template X<U>::` => `template X<U>::`
+ SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
+ auto SR = NNSLoc.getLocalSourceRange();
- auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
- // Get `UnqualifiedId` from `DeclRefExpr`.
- // FIXME: Extract this logic so that it can be used by `MemberExpr`,
- // and other semantic constructs, now it is tied to `DeclRefExpr`.
- if (!S->hasExplicitTemplateArgs()) {
- Builder.foldNode(Builder.getRange(S->getNameInfo().getSourceRange()),
- unqualifiedId, nullptr);
- } else {
- auto templateIdSourceRange =
- SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
- Builder.foldNode(Builder.getRange(templateIdSourceRange), unqualifiedId,
- nullptr);
+ // The method `NestedNameSpecifierLoc::getLocalSourceRange` *should*
+ // return the desired `SourceRange`, but there is a corner case. For a
+ // `DependentTemplateSpecializationType` this method returns its
+ // qualifiers as well, in other words in the example above this method
+ // returns `T::template X<U>::` instead of only `template X<U>::`
+ if (auto TL = NNSLoc.getTypeLoc()) {
+ if (auto DependentTL =
+ TL.getAs<DependentTemplateSpecializationTypeLoc>()) {
+ // The 'template' keyword is always present in dependent template
+ // specializations. Except in the case of incorrect code
+ // TODO: Treat the case of incorrect code.
+ SR.setBegin(DependentTL.getTemplateKeywordLoc());
+ }
+ }
+
+ return SR;
+ }
+
+ syntax::NodeKind getNameSpecifierKind(const NestedNameSpecifier &NNS) {
+ switch (NNS.getKind()) {
+ case NestedNameSpecifier::Global:
+ return syntax::NodeKind::GlobalNameSpecifier;
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Identifier:
+ return syntax::NodeKind::IdentifierNameSpecifier;
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ return syntax::NodeKind::SimpleTemplateNameSpecifier;
+ case NestedNameSpecifier::TypeSpec: {
+ const auto *NNSType = NNS.getAsType();
+ assert(NNSType);
+ if (isa<DecltypeType>(NNSType))
+ return syntax::NodeKind::DecltypeNameSpecifier;
+ if (isa<TemplateSpecializationType, DependentTemplateSpecializationType>(
+ NNSType))
+ return syntax::NodeKind::SimpleTemplateNameSpecifier;
+ return syntax::NodeKind::IdentifierNameSpecifier;
+ }
+ default:
+ // FIXME: Support Microsoft's __super
+ llvm::report_fatal_error("We don't yet support the __super specifier",
+ true);
+ }
+ }
+
+ syntax::NameSpecifier *
+ buildNameSpecifier(const NestedNameSpecifierLoc &NNSLoc) {
+ assert(NNSLoc.hasQualifier());
+ auto NameSpecifierTokens =
+ Builder.getRange(getLocalSourceRange(NNSLoc)).drop_back();
+ switch (getNameSpecifierKind(*NNSLoc.getNestedNameSpecifier())) {
+ case syntax::NodeKind::GlobalNameSpecifier:
+ return new (allocator()) syntax::GlobalNameSpecifier;
+ case syntax::NodeKind::IdentifierNameSpecifier: {
+ assert(NameSpecifierTokens.size() == 1);
+ Builder.markChildToken(NameSpecifierTokens.begin(),
+ syntax::NodeRole::Unknown);
+ auto *NS = new (allocator()) syntax::IdentifierNameSpecifier;
+ Builder.foldNode(NameSpecifierTokens, NS, nullptr);
+ return NS;
+ }
+ case syntax::NodeKind::SimpleTemplateNameSpecifier: {
+ // TODO: Build `SimpleTemplateNameSpecifier` children and implement
+ // accessors to them.
+ // Be aware, we cannot do that simply by calling `TraverseTypeLoc`,
+ // some `TypeLoc`s have inside them the previous name specifier and
+ // we want to treat them independently.
+ auto *NS = new (allocator()) syntax::SimpleTemplateNameSpecifier;
+ Builder.foldNode(NameSpecifierTokens, NS, nullptr);
+ return NS;
+ }
+ case syntax::NodeKind::DecltypeNameSpecifier: {
+ const auto TL = NNSLoc.getTypeLoc().castAs<DecltypeTypeLoc>();
+ if (!RecursiveASTVisitor::TraverseDecltypeTypeLoc(TL))
+ return nullptr;
+ auto *NS = new (allocator()) syntax::DecltypeNameSpecifier;
+ // TODO: Implement accessor to `DecltypeNameSpecifier` inner
+ // `DecltypeTypeLoc`.
+ // For that add mapping from `TypeLoc` to `syntax::Node*` then:
+ // Builder.markChild(TypeLoc, syntax::NodeRole);
+ Builder.foldNode(NameSpecifierTokens, NS, nullptr);
+ return NS;
+ }
+ default:
+ llvm_unreachable("getChildKind() does not return this value");
+ }
+ }
+
+ // To build syntax tree nodes for NestedNameSpecifierLoc we override
+ // Traverse instead of WalkUpFrom because we want to traverse the children
+ // ourselves and build a list instead of a nested tree of name specifier
+ // prefixes.
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc) {
+ if (!QualifierLoc)
+ return true;
+ for (auto It = QualifierLoc; It; It = It.getPrefix()) {
+ auto *NS = buildNameSpecifier(It);
+ if (!NS)
+ return false;
+ Builder.markChild(NS, syntax::NodeRole::ListElement);
+ Builder.markChildToken(It.getEndLoc(), syntax::NodeRole::ListDelimiter);
+ }
+ Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()),
+ new (allocator()) syntax::NestedNameSpecifier,
+ QualifierLoc);
+ return true;
+ }
+
+ syntax::IdExpression *buildIdExpression(NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKeywordLoc,
+ SourceRange UnqualifiedIdLoc,
+ ASTPtr From) {
+ if (QualifierLoc) {
+ Builder.markChild(QualifierLoc, syntax::NodeRole::Qualifier);
+ if (TemplateKeywordLoc.isValid())
+ Builder.markChildToken(TemplateKeywordLoc,
+ syntax::NodeRole::TemplateKeyword);
+ }
+
+ auto *TheUnqualifiedId = new (allocator()) syntax::UnqualifiedId;
+ Builder.foldNode(Builder.getRange(UnqualifiedIdLoc), TheUnqualifiedId,
+ nullptr);
+ Builder.markChild(TheUnqualifiedId, syntax::NodeRole::UnqualifiedId);
+
+ auto IdExpressionBeginLoc =
+ QualifierLoc ? QualifierLoc.getBeginLoc() : UnqualifiedIdLoc.getBegin();
+
+ auto *TheIdExpression = new (allocator()) syntax::IdExpression;
+ Builder.foldNode(
+ Builder.getRange(IdExpressionBeginLoc, UnqualifiedIdLoc.getEnd()),
+ TheIdExpression, From);
+
+ return TheIdExpression;
+ }
+
+ bool WalkUpFromMemberExpr(MemberExpr *S) {
+ // For `MemberExpr` with implicit `this->` we generate a simple
+ // `id-expression` syntax node, beacuse an implicit `member-expression` is
+ // syntactically undistinguishable from an `id-expression`
+ if (S->isImplicitAccess()) {
+ buildIdExpression(S->getQualifierLoc(), S->getTemplateKeywordLoc(),
+ SourceRange(S->getMemberLoc(), S->getEndLoc()), S);
+ return true;
}
- Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
+
+ auto *TheIdExpression = buildIdExpression(
+ S->getQualifierLoc(), S->getTemplateKeywordLoc(),
+ SourceRange(S->getMemberLoc(), S->getEndLoc()), nullptr);
+
+ Builder.markChild(TheIdExpression, syntax::NodeRole::Member);
+
+ Builder.markExprChild(S->getBase(), syntax::NodeRole::Object);
+ Builder.markChildToken(S->getOperatorLoc(), syntax::NodeRole::AccessToken);
Builder.foldNode(Builder.getExprRange(S),
- new (allocator()) syntax::IdExpression, S);
+ new (allocator()) syntax::MemberExpression, S);
+ return true;
+ }
+
+ bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
+ buildIdExpression(S->getQualifierLoc(), S->getTemplateKeywordLoc(),
+ SourceRange(S->getLocation(), S->getEndLoc()), S);
+
+ return true;
+ }
+
+ // Same logic as DeclRefExpr.
+ bool WalkUpFromDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
+ buildIdExpression(S->getQualifierLoc(), S->getTemplateKeywordLoc(),
+ SourceRange(S->getLocation(), S->getEndLoc()), S);
+
+ return true;
+ }
+
+ bool WalkUpFromCXXThisExpr(CXXThisExpr *S) {
+ if (!S->isImplicit()) {
+ Builder.markChildToken(S->getLocation(),
+ syntax::NodeRole::IntroducerKeyword);
+ Builder.foldNode(Builder.getExprRange(S),
+ new (allocator()) syntax::ThisExpression, S);
+ }
return true;
}
bool WalkUpFromParenExpr(ParenExpr *S) {
Builder.markChildToken(S->getLParen(), syntax::NodeRole::OpenParen);
- Builder.markExprChild(S->getSubExpr(),
- syntax::NodeRole::ParenExpression_subExpression);
+ Builder.markExprChild(S->getSubExpr(), syntax::NodeRole::SubExpression);
Builder.markChildToken(S->getRParen(), syntax::NodeRole::CloseParen);
Builder.foldNode(Builder.getExprRange(S),
new (allocator()) syntax::ParenExpression, S);
@@ -837,9 +1134,8 @@ public:
bool WalkUpFromUnaryOperator(UnaryOperator *S) {
Builder.markChildToken(S->getOperatorLoc(),
- syntax::NodeRole::OperatorExpression_operatorToken);
- Builder.markExprChild(S->getSubExpr(),
- syntax::NodeRole::UnaryOperatorExpression_operand);
+ syntax::NodeRole::OperatorToken);
+ Builder.markExprChild(S->getSubExpr(), syntax::NodeRole::Operand);
if (S->isPostfix())
Builder.foldNode(Builder.getExprRange(S),
@@ -854,79 +1150,143 @@ public:
}
bool WalkUpFromBinaryOperator(BinaryOperator *S) {
- Builder.markExprChild(
- S->getLHS(), syntax::NodeRole::BinaryOperatorExpression_leftHandSide);
+ Builder.markExprChild(S->getLHS(), syntax::NodeRole::LeftHandSide);
Builder.markChildToken(S->getOperatorLoc(),
- syntax::NodeRole::OperatorExpression_operatorToken);
- Builder.markExprChild(
- S->getRHS(), syntax::NodeRole::BinaryOperatorExpression_rightHandSide);
+ syntax::NodeRole::OperatorToken);
+ Builder.markExprChild(S->getRHS(), syntax::NodeRole::RightHandSide);
Builder.foldNode(Builder.getExprRange(S),
new (allocator()) syntax::BinaryOperatorExpression, S);
return true;
}
+ /// Builds `CallArguments` syntax node from arguments that appear in source
+ /// code, i.e. not default arguments.
+ syntax::CallArguments *
+ buildCallArguments(CallExpr::arg_range ArgsAndDefaultArgs) {
+ auto Args = dropDefaultArgs(ArgsAndDefaultArgs);
+ for (auto *Arg : Args) {
+ Builder.markExprChild(Arg, syntax::NodeRole::ListElement);
+ const auto *DelimiterToken =
+ std::next(Builder.findToken(Arg->getEndLoc()));
+ if (DelimiterToken->kind() == clang::tok::TokenKind::comma)
+ Builder.markChildToken(DelimiterToken, syntax::NodeRole::ListDelimiter);
+ }
+
+ auto *Arguments = new (allocator()) syntax::CallArguments;
+ if (!Args.empty())
+ Builder.foldNode(Builder.getRange((*Args.begin())->getBeginLoc(),
+ (*(Args.end() - 1))->getEndLoc()),
+ Arguments, nullptr);
+
+ return Arguments;
+ }
+
+ bool WalkUpFromCallExpr(CallExpr *S) {
+ Builder.markExprChild(S->getCallee(), syntax::NodeRole::Callee);
+
+ const auto *LParenToken =
+ std::next(Builder.findToken(S->getCallee()->getEndLoc()));
+ // FIXME: Assert that `LParenToken` is indeed a `l_paren` once we have fixed
+ // the test on decltype desctructors.
+ if (LParenToken->kind() == clang::tok::l_paren)
+ Builder.markChildToken(LParenToken, syntax::NodeRole::OpenParen);
+
+ Builder.markChild(buildCallArguments(S->arguments()),
+ syntax::NodeRole::Arguments);
+
+ Builder.markChildToken(S->getRParenLoc(), syntax::NodeRole::CloseParen);
+
+ Builder.foldNode(Builder.getRange(S->getSourceRange()),
+ new (allocator()) syntax::CallExpression, S);
+ return true;
+ }
+
+ bool WalkUpFromCXXConstructExpr(CXXConstructExpr *S) {
+ // Ignore the implicit calls to default constructors.
+ if ((S->getNumArgs() == 0 || isa<CXXDefaultArgExpr>(S->getArg(0))) &&
+ S->getParenOrBraceRange().isInvalid())
+ return true;
+ return RecursiveASTVisitor::WalkUpFromCXXConstructExpr(S);
+ }
+
bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
- if (getOperatorNodeKind(*S) ==
- syntax::NodeKind::PostfixUnaryOperatorExpression) {
+ // To construct a syntax tree of the same shape for calls to built-in and
+ // user-defined operators, ignore the `DeclRefExpr` that refers to the
+ // operator and treat it as a simple token. Do that by traversing
+ // arguments instead of children.
+ for (auto *child : S->arguments()) {
// A postfix unary operator is declared as taking two operands. The
// second operand is used to distinguish from its prefix counterpart. In
// the semantic AST this "phantom" operand is represented as a
// `IntegerLiteral` with invalid `SourceLocation`. We skip visiting this
// operand because it does not correspond to anything written in source
- // code
- for (auto *child : S->children()) {
- if (child->getSourceRange().isInvalid())
- continue;
- if (!TraverseStmt(child))
- return false;
+ // code.
+ if (child->getSourceRange().isInvalid()) {
+ assert(getOperatorNodeKind(*S) ==
+ syntax::NodeKind::PostfixUnaryOperatorExpression);
+ continue;
}
- return WalkUpFromCXXOperatorCallExpr(S);
- } else
- return RecursiveASTVisitor::TraverseCXXOperatorCallExpr(S);
+ if (!TraverseStmt(child))
+ return false;
+ }
+ return WalkUpFromCXXOperatorCallExpr(S);
}
bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
switch (getOperatorNodeKind(*S)) {
case syntax::NodeKind::BinaryOperatorExpression:
- Builder.markExprChild(
- S->getArg(0),
- syntax::NodeRole::BinaryOperatorExpression_leftHandSide);
- Builder.markChildToken(
- S->getOperatorLoc(),
- syntax::NodeRole::OperatorExpression_operatorToken);
- Builder.markExprChild(
- S->getArg(1),
- syntax::NodeRole::BinaryOperatorExpression_rightHandSide);
+ Builder.markExprChild(S->getArg(0), syntax::NodeRole::LeftHandSide);
+ Builder.markChildToken(S->getOperatorLoc(),
+ syntax::NodeRole::OperatorToken);
+ Builder.markExprChild(S->getArg(1), syntax::NodeRole::RightHandSide);
Builder.foldNode(Builder.getExprRange(S),
new (allocator()) syntax::BinaryOperatorExpression, S);
return true;
case syntax::NodeKind::PrefixUnaryOperatorExpression:
- Builder.markChildToken(
- S->getOperatorLoc(),
- syntax::NodeRole::OperatorExpression_operatorToken);
- Builder.markExprChild(S->getArg(0),
- syntax::NodeRole::UnaryOperatorExpression_operand);
+ Builder.markChildToken(S->getOperatorLoc(),
+ syntax::NodeRole::OperatorToken);
+ Builder.markExprChild(S->getArg(0), syntax::NodeRole::Operand);
Builder.foldNode(Builder.getExprRange(S),
new (allocator()) syntax::PrefixUnaryOperatorExpression,
S);
return true;
case syntax::NodeKind::PostfixUnaryOperatorExpression:
- Builder.markChildToken(
- S->getOperatorLoc(),
- syntax::NodeRole::OperatorExpression_operatorToken);
- Builder.markExprChild(S->getArg(0),
- syntax::NodeRole::UnaryOperatorExpression_operand);
+ Builder.markChildToken(S->getOperatorLoc(),
+ syntax::NodeRole::OperatorToken);
+ Builder.markExprChild(S->getArg(0), syntax::NodeRole::Operand);
Builder.foldNode(Builder.getExprRange(S),
new (allocator()) syntax::PostfixUnaryOperatorExpression,
S);
return true;
+ case syntax::NodeKind::CallExpression: {
+ Builder.markExprChild(S->getArg(0), syntax::NodeRole::Callee);
+
+ const auto *LParenToken =
+ std::next(Builder.findToken(S->getArg(0)->getEndLoc()));
+ // FIXME: Assert that `LParenToken` is indeed a `l_paren` once we have
+ // fixed the test on decltype desctructors.
+ if (LParenToken->kind() == clang::tok::l_paren)
+ Builder.markChildToken(LParenToken, syntax::NodeRole::OpenParen);
+
+ Builder.markChild(buildCallArguments(CallExpr::arg_range(
+ S->arg_begin() + 1, S->arg_end())),
+ syntax::NodeRole::Arguments);
+
+ Builder.markChildToken(S->getRParenLoc(), syntax::NodeRole::CloseParen);
+
+ Builder.foldNode(Builder.getRange(S->getSourceRange()),
+ new (allocator()) syntax::CallExpression, S);
+ return true;
+ }
case syntax::NodeKind::UnknownExpression:
- return RecursiveASTVisitor::WalkUpFromCXXOperatorCallExpr(S);
+ return WalkUpFromExpr(S);
default:
llvm_unreachable("getOperatorNodeKind() does not return this value");
}
}
+ bool WalkUpFromCXXDefaultArgExpr(CXXDefaultArgExpr *S) { return true; }
+
bool WalkUpFromNamespaceDecl(NamespaceDecl *S) {
auto Tokens = Builder.getDeclarationRange(S);
if (Tokens.front().kind() == tok::coloncolon) {
@@ -939,6 +1299,8 @@ public:
return true;
}
+ // FIXME: Deleting the `TraverseParenTypeLoc` override doesn't change test
+ // results. Find test coverage or remove it.
bool TraverseParenTypeLoc(ParenTypeLoc L) {
// We reverse order of traversal to get the proper syntax structure.
if (!WalkUpFromParenTypeLoc(L))
@@ -957,19 +1319,35 @@ public:
// 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.markExprChild(L.getSizeExpr(), syntax::NodeRole::Size);
Builder.markChildToken(L.getRBracketLoc(), syntax::NodeRole::CloseParen);
Builder.foldNode(Builder.getRange(L.getLBracketLoc(), L.getRBracketLoc()),
new (allocator()) syntax::ArraySubscript, L);
return true;
}
+ syntax::ParameterDeclarationList *
+ buildParameterDeclarationList(ArrayRef<ParmVarDecl *> Params) {
+ for (auto *P : Params) {
+ Builder.markChild(P, syntax::NodeRole::ListElement);
+ const auto *DelimiterToken = std::next(Builder.findToken(P->getEndLoc()));
+ if (DelimiterToken->kind() == clang::tok::TokenKind::comma)
+ Builder.markChildToken(DelimiterToken, syntax::NodeRole::ListDelimiter);
+ }
+ auto *Parameters = new (allocator()) syntax::ParameterDeclarationList;
+ if (!Params.empty())
+ Builder.foldNode(Builder.getRange(Params.front()->getBeginLoc(),
+ Params.back()->getEndLoc()),
+ Parameters, nullptr);
+ return Parameters;
+ }
+
bool WalkUpFromFunctionTypeLoc(FunctionTypeLoc L) {
Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen);
- for (auto *P : L.getParams()) {
- Builder.markChild(P, syntax::NodeRole::ParametersAndQualifiers_parameter);
- }
+
+ Builder.markChild(buildParameterDeclarationList(L.getParams()),
+ syntax::NodeRole::Parameters);
+
Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen);
Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()),
new (allocator()) syntax::ParametersAndQualifiers, L);
@@ -980,13 +1358,22 @@ public:
if (!L.getTypePtr()->hasTrailingReturn())
return WalkUpFromFunctionTypeLoc(L);
- auto *TrailingReturnTokens = BuildTrailingReturn(L);
+ auto *TrailingReturnTokens = buildTrailingReturn(L);
// Finish building the node for parameters.
- Builder.markChild(TrailingReturnTokens,
- syntax::NodeRole::ParametersAndQualifiers_trailingReturn);
+ Builder.markChild(TrailingReturnTokens, syntax::NodeRole::TrailingReturn);
return WalkUpFromFunctionTypeLoc(L);
}
+ bool TraverseMemberPointerTypeLoc(MemberPointerTypeLoc L) {
+ // In the source code "void (Y::*mp)()" `MemberPointerTypeLoc` corresponds
+ // to "Y::*" but it points to a `ParenTypeLoc` that corresponds to
+ // "(Y::*mp)" We thus reverse the order of traversal to get the proper
+ // syntax structure.
+ if (!WalkUpFromMemberPointerTypeLoc(L))
+ return false;
+ return TraverseTypeLoc(L.getPointeeLoc());
+ }
+
bool WalkUpFromMemberPointerTypeLoc(MemberPointerTypeLoc L) {
auto SR = L.getLocalSourceRange();
Builder.foldNode(Builder.getRange(SR),
@@ -1021,7 +1408,7 @@ public:
bool WalkUpFromCaseStmt(CaseStmt *S) {
Builder.markChildToken(S->getKeywordLoc(),
syntax::NodeRole::IntroducerKeyword);
- Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value);
+ Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseValue);
Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement);
Builder.foldNode(Builder.getStmtRange(S),
new (allocator()) syntax::CaseStatement, S);
@@ -1039,12 +1426,9 @@ public:
bool WalkUpFromIfStmt(IfStmt *S) {
Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword);
- Builder.markStmtChild(S->getThen(),
- syntax::NodeRole::IfStatement_thenStatement);
- Builder.markChildToken(S->getElseLoc(),
- syntax::NodeRole::IfStatement_elseKeyword);
- Builder.markStmtChild(S->getElse(),
- syntax::NodeRole::IfStatement_elseStatement);
+ Builder.markStmtChild(S->getThen(), syntax::NodeRole::ThenStatement);
+ Builder.markChildToken(S->getElseLoc(), syntax::NodeRole::ElseKeyword);
+ Builder.markStmtChild(S->getElse(), syntax::NodeRole::ElseStatement);
Builder.foldNode(Builder.getStmtRange(S),
new (allocator()) syntax::IfStatement, S);
return true;
@@ -1086,8 +1470,7 @@ public:
bool WalkUpFromReturnStmt(ReturnStmt *S) {
Builder.markChildToken(S->getReturnLoc(),
syntax::NodeRole::IntroducerKeyword);
- Builder.markExprChild(S->getRetValue(),
- syntax::NodeRole::ReturnStatement_value);
+ Builder.markExprChild(S->getRetValue(), syntax::NodeRole::ReturnValue);
Builder.foldNode(Builder.getStmtRange(S),
new (allocator()) syntax::ReturnStatement, S);
return true;
@@ -1108,10 +1491,8 @@ public:
}
bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) {
- Builder.markExprChild(S->getAssertExpr(),
- syntax::NodeRole::StaticAssertDeclaration_condition);
- Builder.markExprChild(S->getMessage(),
- syntax::NodeRole::StaticAssertDeclaration_message);
+ Builder.markExprChild(S->getAssertExpr(), syntax::NodeRole::Condition);
+ Builder.markExprChild(S->getMessage(), syntax::NodeRole::Message);
Builder.foldNode(Builder.getDeclarationRange(S),
new (allocator()) syntax::StaticAssertDeclaration, S);
return true;
@@ -1161,69 +1542,53 @@ public:
}
private:
- template <class T> SourceLocation getQualifiedNameStart(T *D) {
- static_assert((std::is_base_of<DeclaratorDecl, T>::value ||
- std::is_base_of<TypedefNameDecl, T>::value),
- "only DeclaratorDecl and TypedefNameDecl are supported.");
-
- auto DN = D->getDeclName();
- bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo();
- if (IsAnonymous)
- return SourceLocation();
-
- if (const auto *DD = llvm::dyn_cast<DeclaratorDecl>(D)) {
- if (DD->getQualifierLoc()) {
- return DD->getQualifierLoc().getBeginLoc();
- }
- }
-
- return D->getLocation();
- }
-
- SourceRange getInitializerRange(Decl *D) {
- if (auto *V = llvm::dyn_cast<VarDecl>(D)) {
- auto *I = V->getInit();
- // Initializers in range-based-for are not part of the declarator
- if (I && !V->isCXXForRangeDecl())
- return I->getSourceRange();
- }
-
- return SourceRange();
- }
-
/// Folds SimpleDeclarator node (if present) and in case this is the last
/// declarator in the chain it also folds SimpleDeclaration node.
template <class T> bool processDeclaratorAndDeclaration(T *D) {
- SourceRange Initializer = getInitializerRange(D);
- auto Range = getDeclaratorRange(Builder.sourceManager(),
- D->getTypeSourceInfo()->getTypeLoc(),
- getQualifiedNameStart(D), Initializer);
+ auto Range = getDeclaratorRange(
+ Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(),
+ getQualifiedNameStart(D), getInitializerRange(D));
// There doesn't have to be a declarator (e.g. `void foo(int)` only has
// declaration, but no declarator).
- if (Range.getBegin().isValid()) {
- auto *N = new (allocator()) syntax::SimpleDeclarator;
- Builder.foldNode(Builder.getRange(Range), N, nullptr);
- Builder.markChild(N, syntax::NodeRole::SimpleDeclaration_declarator);
+ if (!Range.getBegin().isValid()) {
+ Builder.markChild(new (allocator()) syntax::DeclaratorList,
+ syntax::NodeRole::Declarators);
+ Builder.foldNode(Builder.getDeclarationRange(D),
+ new (allocator()) syntax::SimpleDeclaration, D);
+ return true;
}
- if (Builder.isResponsibleForCreatingDeclaration(D)) {
- Builder.foldNode(Builder.getDeclarationRange(D),
+ auto *N = new (allocator()) syntax::SimpleDeclarator;
+ Builder.foldNode(Builder.getRange(Range), N, nullptr);
+ Builder.markChild(N, syntax::NodeRole::ListElement);
+
+ if (!Builder.isResponsibleForCreatingDeclaration(D)) {
+ // If this is not the last declarator in the declaration we expect a
+ // delimiter after it.
+ const auto *DelimiterToken = std::next(Builder.findToken(Range.getEnd()));
+ if (DelimiterToken->kind() == clang::tok::TokenKind::comma)
+ Builder.markChildToken(DelimiterToken, syntax::NodeRole::ListDelimiter);
+ } else {
+ auto *DL = new (allocator()) syntax::DeclaratorList;
+ auto DeclarationRange = Builder.getDeclarationRange(D);
+ Builder.foldList(DeclarationRange, DL, nullptr);
+
+ Builder.markChild(DL, syntax::NodeRole::Declarators);
+ Builder.foldNode(DeclarationRange,
new (allocator()) syntax::SimpleDeclaration, D);
}
return true;
}
/// Returns the range of the built node.
- syntax::TrailingReturnType *BuildTrailingReturn(FunctionProtoTypeLoc L) {
+ syntax::TrailingReturnType *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());
+ auto ReturnDeclaratorRange = SourceRange(GetStartLoc().Visit(ReturnedType),
+ ReturnedType.getEndLoc());
syntax::SimpleDeclarator *ReturnDeclarator = nullptr;
if (ReturnDeclaratorRange.isValid()) {
ReturnDeclarator = new (allocator()) syntax::SimpleDeclarator;
@@ -1238,8 +1603,7 @@ private:
auto Tokens = llvm::makeArrayRef(Arrow, Return.end());
Builder.markChildToken(Arrow, syntax::NodeRole::ArrowToken);
if (ReturnDeclarator)
- Builder.markChild(ReturnDeclarator,
- syntax::NodeRole::TrailingReturnType_declarator);
+ Builder.markChild(ReturnDeclarator, syntax::NodeRole::Declarator);
auto *R = new (allocator()) syntax::TrailingReturnType;
Builder.foldNode(Tokens, R, L);
return R;
@@ -1253,9 +1617,7 @@ private:
assert(TemplateKW && TemplateKW->kind() == tok::kw_template);
Builder.markChildToken(ExternKW, syntax::NodeRole::ExternKeyword);
Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword);
- Builder.markChild(
- InnerDeclaration,
- syntax::NodeRole::ExplicitTemplateInstantiation_declaration);
+ Builder.markChild(InnerDeclaration, syntax::NodeRole::Declaration);
Builder.foldNode(
Range, new (allocator()) syntax::ExplicitTemplateInstantiation, From);
}
@@ -1268,7 +1630,7 @@ private:
auto *N = new (allocator()) syntax::TemplateDeclaration;
Builder.foldNode(Range, N, From);
- Builder.markChild(N, syntax::NodeRole::TemplateDeclaration_declaration);
+ Builder.markChild(N, syntax::NodeRole::Declaration);
return N;
}
@@ -1306,6 +1668,11 @@ void syntax::TreeBuilder::markChild(ASTPtr N, NodeRole R) {
assert(SN != nullptr);
setRole(SN, R);
}
+void syntax::TreeBuilder::markChild(NestedNameSpecifierLoc NNSLoc, NodeRole R) {
+ auto *SN = Mapping.find(NNSLoc);
+ assert(SN != nullptr);
+ setRole(SN, R);
+}
void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
if (!Child)
@@ -1315,7 +1682,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
if (Expr *ChildExpr = dyn_cast<Expr>(Child)) {
// This is an expression in a statement position, consume the trailing
// semicolon and form an 'ExpressionStatement' node.
- markExprChild(ChildExpr, NodeRole::ExpressionStatement_expression);
+ markExprChild(ChildExpr, NodeRole::Expression);
ChildNode = new (allocator()) syntax::ExpressionStatement;
// (!) 'getStmtRange()' ensures this covers a trailing semicolon.
Pending.foldChildren(Arena, getStmtRange(Child), ChildNode);
@@ -1329,7 +1696,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) {
if (!Child)
return;
- Child = Child->IgnoreImplicit();
+ Child = IgnoreImplicit(Child);
syntax::Tree *ChildNode = Mapping.find(Child);
assert(ChildNode != nullptr);
@@ -1339,14 +1706,14 @@ void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) {
const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const {
if (L.isInvalid())
return nullptr;
- auto It = LocationToToken.find(L.getRawEncoding());
+ auto It = LocationToToken.find(L);
assert(It != LocationToToken.end());
return It->second;
}
-syntax::TranslationUnit *
-syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) {
+syntax::TranslationUnit *syntax::buildSyntaxTree(Arena &A,
+ ASTContext &Context) {
TreeBuilder Builder(A);
- BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext());
+ BuildTreeVisitor(Context, Builder).TraverseAST(Context);
return std::move(Builder).finalize();
}
diff --git a/clang/lib/Tooling/Syntax/ComputeReplacements.cpp b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
index 30b3ee17d092..31e1a40c74b6 100644
--- a/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
+++ b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
@@ -32,13 +32,14 @@ void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) {
private:
void process(const syntax::Node *N) {
if (auto *T = dyn_cast<syntax::Tree>(N)) {
- for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling())
+ for (const auto *C = T->getFirstChild(); C != nullptr;
+ C = C->getNextSibling())
process(C);
return;
}
auto *L = cast<syntax::Leaf>(N);
- if (SpanEnd == L->token() && SpanIsOriginal == L->isOriginal()) {
+ if (SpanEnd == L->getToken() && SpanIsOriginal == L->isOriginal()) {
// Extend the current span.
++SpanEnd;
return;
@@ -47,7 +48,7 @@ void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) {
if (SpanBegin)
Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
// Start recording a new span.
- SpanBegin = L->token();
+ SpanBegin = L->getToken();
SpanEnd = SpanBegin + 1;
SpanIsOriginal = L->isOriginal();
}
@@ -63,8 +64,8 @@ void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) {
syntax::FileRange rangeOfExpanded(const syntax::Arena &A,
llvm::ArrayRef<syntax::Token> Expanded) {
- auto &Buffer = A.tokenBuffer();
- auto &SM = A.sourceManager();
+ const auto &Buffer = A.getTokenBuffer();
+ const auto &SM = A.getSourceManager();
// Check that \p Expanded actually points into expanded tokens.
assert(Buffer.expandedTokens().begin() <= Expanded.begin());
@@ -84,8 +85,8 @@ syntax::FileRange rangeOfExpanded(const syntax::Arena &A,
tooling::Replacements
syntax::computeReplacements(const syntax::Arena &A,
const syntax::TranslationUnit &TU) {
- auto &Buffer = A.tokenBuffer();
- auto &SM = A.sourceManager();
+ const auto &Buffer = A.getTokenBuffer();
+ const auto &SM = A.getSourceManager();
tooling::Replacements Replacements;
// Text inserted by the replacement we are building now.
diff --git a/clang/lib/Tooling/Syntax/Mutations.cpp b/clang/lib/Tooling/Syntax/Mutations.cpp
index 24048b297a11..f8a652219b22 100644
--- a/clang/lib/Tooling/Syntax/Mutations.cpp
+++ b/clang/lib/Tooling/Syntax/Mutations.cpp
@@ -30,14 +30,17 @@ public:
/// Add a new node with a specified role.
static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
assert(Anchor != nullptr);
+ assert(Anchor->Parent != nullptr);
assert(New->Parent == nullptr);
assert(New->NextSibling == nullptr);
- assert(!New->isDetached());
+ assert(New->PreviousSibling == nullptr);
+ assert(New->isDetached());
assert(Role != NodeRole::Detached);
New->setRole(Role);
- auto *P = Anchor->parent();
- P->replaceChildRangeLowLevel(Anchor, Anchor, New);
+ auto *P = Anchor->getParent();
+ P->replaceChildRangeLowLevel(Anchor->getNextSibling(),
+ Anchor->getNextSibling(), New);
P->assertInvariants();
}
@@ -49,43 +52,36 @@ public:
assert(Old->canModify());
assert(New->Parent == nullptr);
assert(New->NextSibling == nullptr);
+ assert(New->PreviousSibling == nullptr);
assert(New->isDetached());
New->Role = Old->Role;
- auto *P = Old->parent();
- P->replaceChildRangeLowLevel(findPrevious(Old), Old->nextSibling(), New);
+ auto *P = Old->getParent();
+ P->replaceChildRangeLowLevel(Old, Old->getNextSibling(), New);
P->assertInvariants();
}
/// Completely remove the node from its parent.
static void remove(syntax::Node *N) {
- auto *P = N->parent();
- P->replaceChildRangeLowLevel(findPrevious(N), N->nextSibling(),
+ assert(N != nullptr);
+ assert(N->Parent != nullptr);
+ assert(N->canModify());
+
+ auto *P = N->getParent();
+ P->replaceChildRangeLowLevel(N, N->getNextSibling(),
/*New=*/nullptr);
P->assertInvariants();
N->assertInvariants();
}
-
-private:
- static syntax::Node *findPrevious(syntax::Node *N) {
- if (N->parent()->firstChild() == N)
- return nullptr;
- for (syntax::Node *C = N->parent()->firstChild(); C != nullptr;
- C = C->nextSibling()) {
- if (C->nextSibling() == N)
- return C;
- }
- llvm_unreachable("could not find a child node");
- }
};
void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
assert(S);
assert(S->canModify());
- if (isa<CompoundStatement>(S->parent())) {
+ if (isa<CompoundStatement>(S->getParent())) {
// A child of CompoundStatement can just be safely removed.
MutationsImpl::remove(S);
return;
diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp
index 2435ae0a91dd..fc6f8ef1a82c 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -10,121 +10,17 @@
using namespace clang;
-llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
+raw_ostream &syntax::operator<<(raw_ostream &OS, NodeKind K) {
switch (K) {
- case NodeKind::Leaf:
- return OS << "Leaf";
- case NodeKind::TranslationUnit:
- return OS << "TranslationUnit";
- case NodeKind::UnknownExpression:
- return OS << "UnknownExpression";
- case NodeKind::ParenExpression:
- return OS << "ParenExpression";
- case NodeKind::IntegerLiteralExpression:
- return OS << "IntegerLiteralExpression";
- case NodeKind::CharacterLiteralExpression:
- return OS << "CharacterLiteralExpression";
- case NodeKind::FloatingLiteralExpression:
- return OS << "FloatingLiteralExpression";
- case NodeKind::StringLiteralExpression:
- return OS << "StringLiteralExpression";
- case NodeKind::BoolLiteralExpression:
- return OS << "BoolLiteralExpression";
- case NodeKind::CxxNullPtrExpression:
- return OS << "CxxNullPtrExpression";
- case NodeKind::IntegerUserDefinedLiteralExpression:
- return OS << "IntegerUserDefinedLiteralExpression";
- case NodeKind::FloatUserDefinedLiteralExpression:
- return OS << "FloatUserDefinedLiteralExpression";
- case NodeKind::CharUserDefinedLiteralExpression:
- return OS << "CharUserDefinedLiteralExpression";
- case NodeKind::StringUserDefinedLiteralExpression:
- return OS << "StringUserDefinedLiteralExpression";
- case NodeKind::PrefixUnaryOperatorExpression:
- return OS << "PrefixUnaryOperatorExpression";
- case NodeKind::PostfixUnaryOperatorExpression:
- return OS << "PostfixUnaryOperatorExpression";
- case NodeKind::BinaryOperatorExpression:
- return OS << "BinaryOperatorExpression";
- case NodeKind::UnqualifiedId:
- return OS << "UnqualifiedId";
- case NodeKind::IdExpression:
- return OS << "IdExpression";
- case NodeKind::UnknownStatement:
- return OS << "UnknownStatement";
- case NodeKind::DeclarationStatement:
- return OS << "DeclarationStatement";
- case NodeKind::EmptyStatement:
- return OS << "EmptyStatement";
- case NodeKind::SwitchStatement:
- return OS << "SwitchStatement";
- case NodeKind::CaseStatement:
- return OS << "CaseStatement";
- case NodeKind::DefaultStatement:
- return OS << "DefaultStatement";
- case NodeKind::IfStatement:
- return OS << "IfStatement";
- case NodeKind::ForStatement:
- return OS << "ForStatement";
- case NodeKind::WhileStatement:
- return OS << "WhileStatement";
- case NodeKind::ContinueStatement:
- return OS << "ContinueStatement";
- case NodeKind::BreakStatement:
- return OS << "BreakStatement";
- case NodeKind::ReturnStatement:
- return OS << "ReturnStatement";
- case NodeKind::RangeBasedForStatement:
- return OS << "RangeBasedForStatement";
- case NodeKind::ExpressionStatement:
- return OS << "ExpressionStatement";
- case NodeKind::CompoundStatement:
- return OS << "CompoundStatement";
- case NodeKind::UnknownDeclaration:
- return OS << "UnknownDeclaration";
- case NodeKind::EmptyDeclaration:
- return OS << "EmptyDeclaration";
- case NodeKind::StaticAssertDeclaration:
- return OS << "StaticAssertDeclaration";
- case NodeKind::LinkageSpecificationDeclaration:
- return OS << "LinkageSpecificationDeclaration";
- case NodeKind::SimpleDeclaration:
- return OS << "SimpleDeclaration";
- case NodeKind::TemplateDeclaration:
- return OS << "TemplateDeclaration";
- case NodeKind::ExplicitTemplateInstantiation:
- return OS << "ExplicitTemplateInstantiation";
- case NodeKind::NamespaceDefinition:
- return OS << "NamespaceDefinition";
- case NodeKind::NamespaceAliasDefinition:
- return OS << "NamespaceAliasDefinition";
- case NodeKind::UsingNamespaceDirective:
- return OS << "UsingNamespaceDirective";
- case NodeKind::UsingDeclaration:
- 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";
- case NodeKind::NameSpecifier:
- return OS << "NameSpecifier";
- case NodeKind::NestedNameSpecifier:
- return OS << "NestedNameSpecifier";
+#define CONCRETE_NODE(Kind, Parent) \
+ case NodeKind::Kind: \
+ return OS << #Kind;
+#include "clang/Tooling/Syntax/Nodes.inc"
}
llvm_unreachable("unknown node kind");
}
-llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
+raw_ostream &syntax::operator<<(raw_ostream &OS, NodeRole R) {
switch (R) {
case syntax::NodeRole::Detached:
return OS << "Detached";
@@ -142,384 +38,404 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
return OS << "ArrowToken";
case syntax::NodeRole::ExternKeyword:
return OS << "ExternKeyword";
+ case syntax::NodeRole::TemplateKeyword:
+ return OS << "TemplateKeyword";
case syntax::NodeRole::BodyStatement:
return OS << "BodyStatement";
- case syntax::NodeRole::CaseStatement_value:
- return OS << "CaseStatement_value";
- case syntax::NodeRole::IfStatement_thenStatement:
- return OS << "IfStatement_thenStatement";
- case syntax::NodeRole::IfStatement_elseKeyword:
- return OS << "IfStatement_elseKeyword";
- case syntax::NodeRole::IfStatement_elseStatement:
- return OS << "IfStatement_elseStatement";
- case syntax::NodeRole::OperatorExpression_operatorToken:
- return OS << "OperatorExpression_operatorToken";
- case syntax::NodeRole::UnaryOperatorExpression_operand:
- return OS << "UnaryOperatorExpression_operand";
- case syntax::NodeRole::BinaryOperatorExpression_leftHandSide:
- return OS << "BinaryOperatorExpression_leftHandSide";
- case syntax::NodeRole::BinaryOperatorExpression_rightHandSide:
- return OS << "BinaryOperatorExpression_rightHandSide";
- case syntax::NodeRole::ReturnStatement_value:
- return OS << "ReturnStatement_value";
- case syntax::NodeRole::ExpressionStatement_expression:
- return OS << "ExpressionStatement_expression";
- case syntax::NodeRole::CompoundStatement_statement:
- return OS << "CompoundStatement_statement";
- case syntax::NodeRole::StaticAssertDeclaration_condition:
- 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::TemplateDeclaration_declaration:
- return OS << "TemplateDeclaration_declaration";
- case syntax::NodeRole::ExplicitTemplateInstantiation_declaration:
- return OS << "ExplicitTemplateInstantiation_declaration";
- case syntax::NodeRole::ArraySubscript_sizeExpression:
- return OS << "ArraySubscript_sizeExpression";
- 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";
- case syntax::NodeRole::IdExpression_id:
- return OS << "IdExpression_id";
- case syntax::NodeRole::IdExpression_qualifier:
- return OS << "IdExpression_qualifier";
- case syntax::NodeRole::NestedNameSpecifier_specifier:
- return OS << "NestedNameSpecifier_specifier";
- case syntax::NodeRole::ParenExpression_subExpression:
- return OS << "ParenExpression_subExpression";
+ case syntax::NodeRole::ListElement:
+ return OS << "ListElement";
+ case syntax::NodeRole::ListDelimiter:
+ return OS << "ListDelimiter";
+ case syntax::NodeRole::CaseValue:
+ return OS << "CaseValue";
+ case syntax::NodeRole::ReturnValue:
+ return OS << "ReturnValue";
+ case syntax::NodeRole::ThenStatement:
+ return OS << "ThenStatement";
+ case syntax::NodeRole::ElseKeyword:
+ return OS << "ElseKeyword";
+ case syntax::NodeRole::ElseStatement:
+ return OS << "ElseStatement";
+ case syntax::NodeRole::OperatorToken:
+ return OS << "OperatorToken";
+ case syntax::NodeRole::Operand:
+ return OS << "Operand";
+ case syntax::NodeRole::LeftHandSide:
+ return OS << "LeftHandSide";
+ case syntax::NodeRole::RightHandSide:
+ return OS << "RightHandSide";
+ case syntax::NodeRole::Expression:
+ return OS << "Expression";
+ case syntax::NodeRole::Statement:
+ return OS << "Statement";
+ case syntax::NodeRole::Condition:
+ return OS << "Condition";
+ case syntax::NodeRole::Message:
+ return OS << "Message";
+ case syntax::NodeRole::Declarator:
+ return OS << "Declarator";
+ case syntax::NodeRole::Declaration:
+ return OS << "Declaration";
+ case syntax::NodeRole::Size:
+ return OS << "Size";
+ case syntax::NodeRole::Parameters:
+ return OS << "Parameters";
+ case syntax::NodeRole::TrailingReturn:
+ return OS << "TrailingReturn";
+ case syntax::NodeRole::UnqualifiedId:
+ return OS << "UnqualifiedId";
+ case syntax::NodeRole::Qualifier:
+ return OS << "Qualifier";
+ case syntax::NodeRole::SubExpression:
+ return OS << "SubExpression";
+ case syntax::NodeRole::Object:
+ return OS << "Object";
+ case syntax::NodeRole::AccessToken:
+ return OS << "AccessToken";
+ case syntax::NodeRole::Member:
+ return OS << "Member";
+ case syntax::NodeRole::Callee:
+ return OS << "Callee";
+ case syntax::NodeRole::Arguments:
+ return OS << "Arguments";
+ case syntax::NodeRole::Declarators:
+ return OS << "Declarators";
}
llvm_unreachable("invalid role");
}
-std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
+// We could have an interator in list to not pay memory costs of temporary
+// vector
+std::vector<syntax::NameSpecifier *>
+syntax::NestedNameSpecifier::getSpecifiers() {
+ auto SpecifiersAsNodes = getElementsAsNodes();
std::vector<syntax::NameSpecifier *> Children;
- for (auto *C = firstChild(); C; C = C->nextSibling()) {
- assert(C->role() == syntax::NodeRole::NestedNameSpecifier_specifier);
- Children.push_back(llvm::cast<syntax::NameSpecifier>(C));
+ for (const auto &Element : SpecifiersAsNodes) {
+ Children.push_back(llvm::cast<syntax::NameSpecifier>(Element));
}
return Children;
}
-syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() {
- return llvm::cast_or_null<syntax::NestedNameSpecifier>(
- findChild(syntax::NodeRole::IdExpression_qualifier));
-}
-
-syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
- return llvm::cast_or_null<syntax::UnqualifiedId>(
- findChild(syntax::NodeRole::IdExpression_id));
-}
-
-syntax::Leaf *syntax::ParenExpression::openParen() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::OpenParen));
-}
-
-syntax::Expression *syntax::ParenExpression::subExpression() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::ParenExpression_subExpression));
-}
-
-syntax::Leaf *syntax::ParenExpression::closeParen() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::CloseParen));
-}
-
-syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>>
+syntax::NestedNameSpecifier::getSpecifiersAndDoubleColons() {
+ auto SpecifiersAsNodesAndDoubleColons = getElementsAsNodesAndDelimiters();
+ std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>>
+ Children;
+ for (const auto &SpecifierAndDoubleColon : SpecifiersAsNodesAndDoubleColons) {
+ Children.push_back(
+ {llvm::cast<syntax::NameSpecifier>(SpecifierAndDoubleColon.element),
+ SpecifierAndDoubleColon.delimiter});
+ }
+ return Children;
}
-syntax::Leaf *syntax::CharacterLiteralExpression::literalToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::Expression *> syntax::CallArguments::getArguments() {
+ auto ArgumentsAsNodes = getElementsAsNodes();
+ std::vector<syntax::Expression *> Children;
+ for (const auto &ArgumentAsNode : ArgumentsAsNodes) {
+ Children.push_back(llvm::cast<syntax::Expression>(ArgumentAsNode));
+ }
+ return Children;
}
-syntax::Leaf *syntax::FloatingLiteralExpression::literalToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>>
+syntax::CallArguments::getArgumentsAndCommas() {
+ auto ArgumentsAsNodesAndCommas = getElementsAsNodesAndDelimiters();
+ std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>> Children;
+ for (const auto &ArgumentAsNodeAndComma : ArgumentsAsNodesAndCommas) {
+ Children.push_back(
+ {llvm::cast<syntax::Expression>(ArgumentAsNodeAndComma.element),
+ ArgumentAsNodeAndComma.delimiter});
+ }
+ return Children;
}
-syntax::Leaf *syntax::StringLiteralExpression::literalToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::SimpleDeclaration *>
+syntax::ParameterDeclarationList::getParameterDeclarations() {
+ auto ParametersAsNodes = getElementsAsNodes();
+ std::vector<syntax::SimpleDeclaration *> Children;
+ for (const auto &ParameterAsNode : ParametersAsNodes) {
+ Children.push_back(llvm::cast<syntax::SimpleDeclaration>(ParameterAsNode));
+ }
+ return Children;
}
-syntax::Leaf *syntax::BoolLiteralExpression::literalToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>>
+syntax::ParameterDeclarationList::getParametersAndCommas() {
+ auto ParametersAsNodesAndCommas = getElementsAsNodesAndDelimiters();
+ std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>>
+ Children;
+ for (const auto &ParameterAsNodeAndComma : ParametersAsNodesAndCommas) {
+ Children.push_back(
+ {llvm::cast<syntax::SimpleDeclaration>(ParameterAsNodeAndComma.element),
+ ParameterAsNodeAndComma.delimiter});
+ }
+ return Children;
}
-syntax::Leaf *syntax::CxxNullPtrExpression::nullPtrKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::SimpleDeclarator *>
+syntax::DeclaratorList::getDeclarators() {
+ auto DeclaratorsAsNodes = getElementsAsNodes();
+ std::vector<syntax::SimpleDeclarator *> Children;
+ for (const auto &DeclaratorAsNode : DeclaratorsAsNodes) {
+ Children.push_back(llvm::cast<syntax::SimpleDeclarator>(DeclaratorAsNode));
+ }
+ return Children;
}
-syntax::Leaf *syntax::UserDefinedLiteralExpression::literalToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::LiteralToken));
+std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>>
+syntax::DeclaratorList::getDeclaratorsAndCommas() {
+ auto DeclaratorsAsNodesAndCommas = getElementsAsNodesAndDelimiters();
+ std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>>
+ Children;
+ for (const auto &DeclaratorAsNodeAndComma : DeclaratorsAsNodesAndCommas) {
+ Children.push_back(
+ {llvm::cast<syntax::SimpleDeclarator>(DeclaratorAsNodeAndComma.element),
+ DeclaratorAsNodeAndComma.delimiter});
+ }
+ return Children;
}
-syntax::Expression *syntax::BinaryOperatorExpression::lhs() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::BinaryOperatorExpression_leftHandSide));
+syntax::Expression *syntax::BinaryOperatorExpression::getLhs() {
+ return cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::LeftHandSide));
}
-syntax::Leaf *syntax::UnaryOperatorExpression::operatorToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::OperatorExpression_operatorToken));
+syntax::Leaf *syntax::UnaryOperatorExpression::getOperatorToken() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OperatorToken));
}
-syntax::Expression *syntax::UnaryOperatorExpression::operand() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::UnaryOperatorExpression_operand));
+syntax::Expression *syntax::UnaryOperatorExpression::getOperand() {
+ return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Operand));
}
-syntax::Leaf *syntax::BinaryOperatorExpression::operatorToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::OperatorExpression_operatorToken));
+syntax::Leaf *syntax::BinaryOperatorExpression::getOperatorToken() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OperatorToken));
}
-syntax::Expression *syntax::BinaryOperatorExpression::rhs() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide));
+syntax::Expression *syntax::BinaryOperatorExpression::getRhs() {
+ return cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::RightHandSide));
}
-syntax::Leaf *syntax::SwitchStatement::switchKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::SwitchStatement::getSwitchKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Statement *syntax::SwitchStatement::body() {
- return llvm::cast_or_null<syntax::Statement>(
+syntax::Statement *syntax::SwitchStatement::getBody() {
+ return cast_or_null<syntax::Statement>(
findChild(syntax::NodeRole::BodyStatement));
}
-syntax::Leaf *syntax::CaseStatement::caseKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::CaseStatement::getCaseKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Expression *syntax::CaseStatement::value() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::CaseStatement_value));
+syntax::Expression *syntax::CaseStatement::getCaseValue() {
+ return cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::CaseValue));
}
-syntax::Statement *syntax::CaseStatement::body() {
- return llvm::cast_or_null<syntax::Statement>(
+syntax::Statement *syntax::CaseStatement::getBody() {
+ return cast_or_null<syntax::Statement>(
findChild(syntax::NodeRole::BodyStatement));
}
-syntax::Leaf *syntax::DefaultStatement::defaultKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::DefaultStatement::getDefaultKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Statement *syntax::DefaultStatement::body() {
- return llvm::cast_or_null<syntax::Statement>(
+syntax::Statement *syntax::DefaultStatement::getBody() {
+ return cast_or_null<syntax::Statement>(
findChild(syntax::NodeRole::BodyStatement));
}
-syntax::Leaf *syntax::IfStatement::ifKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::IfStatement::getIfKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Statement *syntax::IfStatement::thenStatement() {
- return llvm::cast_or_null<syntax::Statement>(
- findChild(syntax::NodeRole::IfStatement_thenStatement));
+syntax::Statement *syntax::IfStatement::getThenStatement() {
+ return cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::ThenStatement));
}
-syntax::Leaf *syntax::IfStatement::elseKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::IfStatement_elseKeyword));
+syntax::Leaf *syntax::IfStatement::getElseKeyword() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::ElseKeyword));
}
-syntax::Statement *syntax::IfStatement::elseStatement() {
- return llvm::cast_or_null<syntax::Statement>(
- findChild(syntax::NodeRole::IfStatement_elseStatement));
+syntax::Statement *syntax::IfStatement::getElseStatement() {
+ return cast_or_null<syntax::Statement>(
+ findChild(syntax::NodeRole::ElseStatement));
}
-syntax::Leaf *syntax::ForStatement::forKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::ForStatement::getForKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Statement *syntax::ForStatement::body() {
- return llvm::cast_or_null<syntax::Statement>(
+syntax::Statement *syntax::ForStatement::getBody() {
+ return cast_or_null<syntax::Statement>(
findChild(syntax::NodeRole::BodyStatement));
}
-syntax::Leaf *syntax::WhileStatement::whileKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::WhileStatement::getWhileKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Statement *syntax::WhileStatement::body() {
- return llvm::cast_or_null<syntax::Statement>(
+syntax::Statement *syntax::WhileStatement::getBody() {
+ return cast_or_null<syntax::Statement>(
findChild(syntax::NodeRole::BodyStatement));
}
-syntax::Leaf *syntax::ContinueStatement::continueKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::ContinueStatement::getContinueKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Leaf *syntax::BreakStatement::breakKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::BreakStatement::getBreakKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Leaf *syntax::ReturnStatement::returnKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::ReturnStatement::getReturnKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Expression *syntax::ReturnStatement::value() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::ReturnStatement_value));
+syntax::Expression *syntax::ReturnStatement::getReturnValue() {
+ return cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::ReturnValue));
}
-syntax::Leaf *syntax::RangeBasedForStatement::forKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::RangeBasedForStatement::getForKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Statement *syntax::RangeBasedForStatement::body() {
- return llvm::cast_or_null<syntax::Statement>(
+syntax::Statement *syntax::RangeBasedForStatement::getBody() {
+ return cast_or_null<syntax::Statement>(
findChild(syntax::NodeRole::BodyStatement));
}
-syntax::Expression *syntax::ExpressionStatement::expression() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::ExpressionStatement_expression));
+syntax::Expression *syntax::ExpressionStatement::getExpression() {
+ return cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::Expression));
}
-syntax::Leaf *syntax::CompoundStatement::lbrace() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::OpenParen));
+syntax::Leaf *syntax::CompoundStatement::getLbrace() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OpenParen));
}
-std::vector<syntax::Statement *> syntax::CompoundStatement::statements() {
+std::vector<syntax::Statement *> syntax::CompoundStatement::getStatements() {
std::vector<syntax::Statement *> Children;
- for (auto *C = firstChild(); C; C = C->nextSibling()) {
- assert(C->role() == syntax::NodeRole::CompoundStatement_statement);
- Children.push_back(llvm::cast<syntax::Statement>(C));
+ for (auto *C = getFirstChild(); C; C = C->getNextSibling()) {
+ assert(C->getRole() == syntax::NodeRole::Statement);
+ Children.push_back(cast<syntax::Statement>(C));
}
return Children;
}
-syntax::Leaf *syntax::CompoundStatement::rbrace() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::CloseParen));
+syntax::Leaf *syntax::CompoundStatement::getRbrace() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
}
-syntax::Expression *syntax::StaticAssertDeclaration::condition() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::StaticAssertDeclaration_condition));
+syntax::Expression *syntax::StaticAssertDeclaration::getCondition() {
+ return cast_or_null<syntax::Expression>(
+ findChild(syntax::NodeRole::Condition));
}
-syntax::Expression *syntax::StaticAssertDeclaration::message() {
- return llvm::cast_or_null<syntax::Expression>(
- findChild(syntax::NodeRole::StaticAssertDeclaration_message));
+syntax::Expression *syntax::StaticAssertDeclaration::getMessage() {
+ return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Message));
}
std::vector<syntax::SimpleDeclarator *>
-syntax::SimpleDeclaration::declarators() {
+syntax::SimpleDeclaration::getDeclarators() {
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));
+ for (auto *C = getFirstChild(); C; C = C->getNextSibling()) {
+ if (C->getRole() == syntax::NodeRole::Declarator)
+ Children.push_back(cast<syntax::SimpleDeclarator>(C));
}
return Children;
}
-syntax::Leaf *syntax::TemplateDeclaration::templateKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::TemplateDeclaration::getTemplateKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Declaration *syntax::TemplateDeclaration::declaration() {
- return llvm::cast_or_null<syntax::Declaration>(
- findChild(syntax::NodeRole::TemplateDeclaration_declaration));
+syntax::Declaration *syntax::TemplateDeclaration::getDeclaration() {
+ return cast_or_null<syntax::Declaration>(
+ findChild(syntax::NodeRole::Declaration));
}
-syntax::Leaf *syntax::ExplicitTemplateInstantiation::templateKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
+syntax::Leaf *syntax::ExplicitTemplateInstantiation::getTemplateKeyword() {
+ return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));
}
-syntax::Leaf *syntax::ExplicitTemplateInstantiation::externKeyword() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::ExternKeyword));
+syntax::Leaf *syntax::ExplicitTemplateInstantiation::getExternKeyword() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::ExternKeyword));
}
-syntax::Declaration *syntax::ExplicitTemplateInstantiation::declaration() {
- return llvm::cast_or_null<syntax::Declaration>(
- findChild(syntax::NodeRole::ExplicitTemplateInstantiation_declaration));
+syntax::Declaration *syntax::ExplicitTemplateInstantiation::getDeclaration() {
+ return cast_or_null<syntax::Declaration>(
+ findChild(syntax::NodeRole::Declaration));
}
-syntax::Leaf *syntax::ParenDeclarator::lparen() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::OpenParen));
+syntax::Leaf *syntax::ParenDeclarator::getLparen() {
+ return 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::ParenDeclarator::getRparen() {
+ return 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::Leaf *syntax::ArraySubscript::getLbracket() {
+ return 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::Expression *syntax::ArraySubscript::getSize() {
+ return cast_or_null<syntax::Expression>(findChild(syntax::NodeRole::Size));
}
-syntax::Leaf *syntax::ArraySubscript::rbracket() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::CloseParen));
+syntax::Leaf *syntax::ArraySubscript::getRbracket() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
}
-syntax::Leaf *syntax::TrailingReturnType::arrowToken() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::ArrowToken));
+syntax::Leaf *syntax::TrailingReturnType::getArrowToken() {
+ return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::ArrowToken));
}
-syntax::SimpleDeclarator *syntax::TrailingReturnType::declarator() {
- return llvm::cast_or_null<syntax::SimpleDeclarator>(
- findChild(syntax::NodeRole::TrailingReturnType_declarator));
+syntax::SimpleDeclarator *syntax::TrailingReturnType::getDeclarator() {
+ return cast_or_null<syntax::SimpleDeclarator>(
+ findChild(syntax::NodeRole::Declarator));
}
-syntax::Leaf *syntax::ParametersAndQualifiers::lparen() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::OpenParen));
+syntax::Leaf *syntax::ParametersAndQualifiers::getLparen() {
+ return 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::ParameterDeclarationList *
+syntax::ParametersAndQualifiers::getParameters() {
+ return cast_or_null<syntax::ParameterDeclarationList>(
+ findChild(syntax::NodeRole::Parameters));
}
-syntax::Leaf *syntax::ParametersAndQualifiers::rparen() {
- return llvm::cast_or_null<syntax::Leaf>(
- findChild(syntax::NodeRole::CloseParen));
+syntax::Leaf *syntax::ParametersAndQualifiers::getRparen() {
+ return 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));
+syntax::TrailingReturnType *
+syntax::ParametersAndQualifiers::getTrailingReturn() {
+ return cast_or_null<syntax::TrailingReturnType>(
+ findChild(syntax::NodeRole::TrailingReturn));
}
+
+#define NODE(Kind, Parent) \
+ static_assert(sizeof(syntax::Kind) > 0, "Missing Node subclass definition");
+#include "clang/Tooling/Syntax/Nodes.inc"
diff --git a/clang/lib/Tooling/Syntax/Synthesis.cpp b/clang/lib/Tooling/Syntax/Synthesis.cpp
index aa01a34c761f..ef6492882be6 100644
--- a/clang/lib/Tooling/Syntax/Synthesis.cpp
+++ b/clang/lib/Tooling/Syntax/Synthesis.cpp
@@ -5,13 +5,15 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/TokenKinds.h"
#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Tree.h"
using namespace clang;
/// Exposes private syntax tree APIs required to implement node synthesis.
/// Should not be used for anything else.
-class syntax::FactoryImpl {
+class clang::syntax::FactoryImpl {
public:
static void setCanModify(syntax::Node *N) { N->CanModify = true; }
@@ -19,27 +21,211 @@ public:
syntax::NodeRole R) {
T->prependChildLowLevel(Child, R);
}
+ static void appendChildLowLevel(syntax::Tree *T, syntax::Node *Child,
+ syntax::NodeRole R) {
+ T->appendChildLowLevel(Child, R);
+ }
+
+ static std::pair<FileID, ArrayRef<Token>>
+ lexBuffer(syntax::Arena &A, std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+ return A.lexBuffer(std::move(Buffer));
+ }
};
-clang::syntax::Leaf *syntax::createPunctuation(clang::syntax::Arena &A,
- clang::tok::TokenKind K) {
- auto Tokens = A.lexBuffer(llvm::MemoryBuffer::getMemBuffer(
- clang::tok::getPunctuatorSpelling(K)))
- .second;
+// FIXME: `createLeaf` is based on `syntax::tokenize` internally, as such it
+// doesn't support digraphs or line continuations.
+syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K,
+ StringRef Spelling) {
+ auto Tokens =
+ FactoryImpl::lexBuffer(A, llvm::MemoryBuffer::getMemBufferCopy(Spelling))
+ .second;
assert(Tokens.size() == 1);
- assert(Tokens.front().kind() == K);
- auto *L = new (A.allocator()) clang::syntax::Leaf(Tokens.begin());
- FactoryImpl::setCanModify(L);
- L->assertInvariants();
- return L;
+ assert(Tokens.front().kind() == K &&
+ "spelling is not lexed into the expected kind of token");
+
+ auto *Leaf = new (A.getAllocator()) syntax::Leaf(Tokens.begin());
+ syntax::FactoryImpl::setCanModify(Leaf);
+ Leaf->assertInvariants();
+ return Leaf;
+}
+
+syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K) {
+ const auto *Spelling = tok::getPunctuatorSpelling(K);
+ if (!Spelling)
+ Spelling = tok::getKeywordSpelling(K);
+ assert(Spelling &&
+ "Cannot infer the spelling of the token from its token kind.");
+ return createLeaf(A, K, Spelling);
+}
+
+namespace {
+// Allocates the concrete syntax `Tree` according to its `NodeKind`.
+syntax::Tree *allocateTree(syntax::Arena &A, syntax::NodeKind Kind) {
+ switch (Kind) {
+ case syntax::NodeKind::Leaf:
+ assert(false);
+ break;
+ case syntax::NodeKind::TranslationUnit:
+ return new (A.getAllocator()) syntax::TranslationUnit;
+ case syntax::NodeKind::UnknownExpression:
+ return new (A.getAllocator()) syntax::UnknownExpression;
+ case syntax::NodeKind::ParenExpression:
+ return new (A.getAllocator()) syntax::ParenExpression;
+ case syntax::NodeKind::ThisExpression:
+ return new (A.getAllocator()) syntax::ThisExpression;
+ case syntax::NodeKind::IntegerLiteralExpression:
+ return new (A.getAllocator()) syntax::IntegerLiteralExpression;
+ case syntax::NodeKind::CharacterLiteralExpression:
+ return new (A.getAllocator()) syntax::CharacterLiteralExpression;
+ case syntax::NodeKind::FloatingLiteralExpression:
+ return new (A.getAllocator()) syntax::FloatingLiteralExpression;
+ case syntax::NodeKind::StringLiteralExpression:
+ return new (A.getAllocator()) syntax::StringLiteralExpression;
+ case syntax::NodeKind::BoolLiteralExpression:
+ return new (A.getAllocator()) syntax::BoolLiteralExpression;
+ case syntax::NodeKind::CxxNullPtrExpression:
+ return new (A.getAllocator()) syntax::CxxNullPtrExpression;
+ case syntax::NodeKind::IntegerUserDefinedLiteralExpression:
+ return new (A.getAllocator()) syntax::IntegerUserDefinedLiteralExpression;
+ case syntax::NodeKind::FloatUserDefinedLiteralExpression:
+ return new (A.getAllocator()) syntax::FloatUserDefinedLiteralExpression;
+ case syntax::NodeKind::CharUserDefinedLiteralExpression:
+ return new (A.getAllocator()) syntax::CharUserDefinedLiteralExpression;
+ case syntax::NodeKind::StringUserDefinedLiteralExpression:
+ return new (A.getAllocator()) syntax::StringUserDefinedLiteralExpression;
+ case syntax::NodeKind::PrefixUnaryOperatorExpression:
+ return new (A.getAllocator()) syntax::PrefixUnaryOperatorExpression;
+ case syntax::NodeKind::PostfixUnaryOperatorExpression:
+ return new (A.getAllocator()) syntax::PostfixUnaryOperatorExpression;
+ case syntax::NodeKind::BinaryOperatorExpression:
+ return new (A.getAllocator()) syntax::BinaryOperatorExpression;
+ case syntax::NodeKind::UnqualifiedId:
+ return new (A.getAllocator()) syntax::UnqualifiedId;
+ case syntax::NodeKind::IdExpression:
+ return new (A.getAllocator()) syntax::IdExpression;
+ case syntax::NodeKind::CallExpression:
+ return new (A.getAllocator()) syntax::CallExpression;
+ case syntax::NodeKind::UnknownStatement:
+ return new (A.getAllocator()) syntax::UnknownStatement;
+ case syntax::NodeKind::DeclarationStatement:
+ return new (A.getAllocator()) syntax::DeclarationStatement;
+ case syntax::NodeKind::EmptyStatement:
+ return new (A.getAllocator()) syntax::EmptyStatement;
+ case syntax::NodeKind::SwitchStatement:
+ return new (A.getAllocator()) syntax::SwitchStatement;
+ case syntax::NodeKind::CaseStatement:
+ return new (A.getAllocator()) syntax::CaseStatement;
+ case syntax::NodeKind::DefaultStatement:
+ return new (A.getAllocator()) syntax::DefaultStatement;
+ case syntax::NodeKind::IfStatement:
+ return new (A.getAllocator()) syntax::IfStatement;
+ case syntax::NodeKind::ForStatement:
+ return new (A.getAllocator()) syntax::ForStatement;
+ case syntax::NodeKind::WhileStatement:
+ return new (A.getAllocator()) syntax::WhileStatement;
+ case syntax::NodeKind::ContinueStatement:
+ return new (A.getAllocator()) syntax::ContinueStatement;
+ case syntax::NodeKind::BreakStatement:
+ return new (A.getAllocator()) syntax::BreakStatement;
+ case syntax::NodeKind::ReturnStatement:
+ return new (A.getAllocator()) syntax::ReturnStatement;
+ case syntax::NodeKind::RangeBasedForStatement:
+ return new (A.getAllocator()) syntax::RangeBasedForStatement;
+ case syntax::NodeKind::ExpressionStatement:
+ return new (A.getAllocator()) syntax::ExpressionStatement;
+ case syntax::NodeKind::CompoundStatement:
+ return new (A.getAllocator()) syntax::CompoundStatement;
+ case syntax::NodeKind::UnknownDeclaration:
+ return new (A.getAllocator()) syntax::UnknownDeclaration;
+ case syntax::NodeKind::EmptyDeclaration:
+ return new (A.getAllocator()) syntax::EmptyDeclaration;
+ case syntax::NodeKind::StaticAssertDeclaration:
+ return new (A.getAllocator()) syntax::StaticAssertDeclaration;
+ case syntax::NodeKind::LinkageSpecificationDeclaration:
+ return new (A.getAllocator()) syntax::LinkageSpecificationDeclaration;
+ case syntax::NodeKind::SimpleDeclaration:
+ return new (A.getAllocator()) syntax::SimpleDeclaration;
+ case syntax::NodeKind::TemplateDeclaration:
+ return new (A.getAllocator()) syntax::TemplateDeclaration;
+ case syntax::NodeKind::ExplicitTemplateInstantiation:
+ return new (A.getAllocator()) syntax::ExplicitTemplateInstantiation;
+ case syntax::NodeKind::NamespaceDefinition:
+ return new (A.getAllocator()) syntax::NamespaceDefinition;
+ case syntax::NodeKind::NamespaceAliasDefinition:
+ return new (A.getAllocator()) syntax::NamespaceAliasDefinition;
+ case syntax::NodeKind::UsingNamespaceDirective:
+ return new (A.getAllocator()) syntax::UsingNamespaceDirective;
+ case syntax::NodeKind::UsingDeclaration:
+ return new (A.getAllocator()) syntax::UsingDeclaration;
+ case syntax::NodeKind::TypeAliasDeclaration:
+ return new (A.getAllocator()) syntax::TypeAliasDeclaration;
+ case syntax::NodeKind::SimpleDeclarator:
+ return new (A.getAllocator()) syntax::SimpleDeclarator;
+ case syntax::NodeKind::ParenDeclarator:
+ return new (A.getAllocator()) syntax::ParenDeclarator;
+ case syntax::NodeKind::ArraySubscript:
+ return new (A.getAllocator()) syntax::ArraySubscript;
+ case syntax::NodeKind::TrailingReturnType:
+ return new (A.getAllocator()) syntax::TrailingReturnType;
+ case syntax::NodeKind::ParametersAndQualifiers:
+ return new (A.getAllocator()) syntax::ParametersAndQualifiers;
+ case syntax::NodeKind::MemberPointer:
+ return new (A.getAllocator()) syntax::MemberPointer;
+ case syntax::NodeKind::GlobalNameSpecifier:
+ return new (A.getAllocator()) syntax::GlobalNameSpecifier;
+ case syntax::NodeKind::DecltypeNameSpecifier:
+ return new (A.getAllocator()) syntax::DecltypeNameSpecifier;
+ case syntax::NodeKind::IdentifierNameSpecifier:
+ return new (A.getAllocator()) syntax::IdentifierNameSpecifier;
+ case syntax::NodeKind::SimpleTemplateNameSpecifier:
+ return new (A.getAllocator()) syntax::SimpleTemplateNameSpecifier;
+ case syntax::NodeKind::NestedNameSpecifier:
+ return new (A.getAllocator()) syntax::NestedNameSpecifier;
+ case syntax::NodeKind::MemberExpression:
+ return new (A.getAllocator()) syntax::MemberExpression;
+ case syntax::NodeKind::CallArguments:
+ return new (A.getAllocator()) syntax::CallArguments;
+ case syntax::NodeKind::ParameterDeclarationList:
+ return new (A.getAllocator()) syntax::ParameterDeclarationList;
+ case syntax::NodeKind::DeclaratorList:
+ return new (A.getAllocator()) syntax::DeclaratorList;
+ }
+ llvm_unreachable("unknown node kind");
+}
+} // namespace
+
+syntax::Tree *clang::syntax::createTree(
+ syntax::Arena &A,
+ ArrayRef<std::pair<syntax::Node *, syntax::NodeRole>> Children,
+ syntax::NodeKind K) {
+ auto *T = allocateTree(A, K);
+ FactoryImpl::setCanModify(T);
+ for (const auto &Child : Children)
+ FactoryImpl::appendChildLowLevel(T, Child.first, Child.second);
+
+ T->assertInvariants();
+ return T;
+}
+
+syntax::Node *clang::syntax::deepCopyExpandingMacros(syntax::Arena &A,
+ const syntax::Node *N) {
+ if (const auto *L = dyn_cast<syntax::Leaf>(N))
+ // `L->getToken()` gives us the expanded token, thus we implicitly expand
+ // any macros here.
+ return createLeaf(A, L->getToken()->kind(),
+ L->getToken()->text(A.getSourceManager()));
+
+ const auto *T = cast<syntax::Tree>(N);
+ std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children;
+ for (const auto *Child = T->getFirstChild(); Child;
+ Child = Child->getNextSibling())
+ Children.push_back({deepCopyExpandingMacros(A, Child), Child->getRole()});
+
+ return createTree(A, Children, N->getKind());
}
-clang::syntax::EmptyStatement *
-syntax::createEmptyStatement(clang::syntax::Arena &A) {
- auto *S = new (A.allocator()) clang::syntax::EmptyStatement;
- FactoryImpl::setCanModify(S);
- FactoryImpl::prependChildLowLevel(S, createPunctuation(A, clang::tok::semi),
- NodeRole::Unknown);
- S->assertInvariants();
- return S;
+syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) {
+ return cast<EmptyStatement>(
+ createTree(A, {{createLeaf(A, tok::semi), NodeRole::Unknown}},
+ NodeKind::EmptyStatement));
}
diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp
index c6b904822b8b..234df9cb7182 100644
--- a/clang/lib/Tooling/Syntax/Tokens.cpp
+++ b/clang/lib/Tooling/Syntax/Tokens.cpp
@@ -249,22 +249,7 @@ llvm::SmallVector<llvm::ArrayRef<syntax::Token>, 1>
TokenBuffer::expandedForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
if (Spelled.empty())
return {};
- assert(Spelled.front().location().isFileID());
-
- auto FID = sourceManager().getFileID(Spelled.front().location());
- auto It = Files.find(FID);
- assert(It != Files.end());
-
- const MarkedFile &File = It->second;
- // `Spelled` must be a subrange of `File.SpelledTokens`.
- assert(File.SpelledTokens.data() <= Spelled.data());
- assert(&Spelled.back() <=
- File.SpelledTokens.data() + File.SpelledTokens.size());
-#ifndef NDEBUG
- auto T1 = Spelled.back().location();
- auto T2 = File.SpelledTokens.back().location();
- assert(T1 == T2 || sourceManager().isBeforeInTranslationUnit(T1, T2));
-#endif
+ const auto &File = fileForSpelled(Spelled);
auto *FrontMapping = mappingStartingBeforeSpelled(File, &Spelled.front());
unsigned SpelledFrontI = &Spelled.front() - File.SpelledTokens.data();
@@ -395,16 +380,39 @@ TokenBuffer::spelledForExpanded(llvm::ArrayRef<syntax::Token> Expanded) const {
: LastSpelled + 1);
}
+TokenBuffer::Expansion TokenBuffer::makeExpansion(const MarkedFile &F,
+ const Mapping &M) const {
+ Expansion E;
+ E.Spelled = llvm::makeArrayRef(F.SpelledTokens.data() + M.BeginSpelled,
+ F.SpelledTokens.data() + M.EndSpelled);
+ E.Expanded = llvm::makeArrayRef(ExpandedTokens.data() + M.BeginExpanded,
+ ExpandedTokens.data() + M.EndExpanded);
+ return E;
+}
+
+const TokenBuffer::MarkedFile &
+TokenBuffer::fileForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
+ assert(!Spelled.empty());
+ assert(Spelled.front().location().isFileID() && "not a spelled token");
+ auto FileIt = Files.find(SourceMgr->getFileID(Spelled.front().location()));
+ assert(FileIt != Files.end() && "file not tracked by token buffer");
+ const auto &File = FileIt->second;
+ assert(File.SpelledTokens.data() <= Spelled.data() &&
+ Spelled.end() <=
+ (File.SpelledTokens.data() + File.SpelledTokens.size()) &&
+ "Tokens not in spelled range");
+#ifndef NDEBUG
+ auto T1 = Spelled.back().location();
+ auto T2 = File.SpelledTokens.back().location();
+ assert(T1 == T2 || sourceManager().isBeforeInTranslationUnit(T1, T2));
+#endif
+ return File;
+}
+
llvm::Optional<TokenBuffer::Expansion>
TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
assert(Spelled);
- assert(Spelled->location().isFileID() && "not a spelled token");
- auto FileIt = Files.find(SourceMgr->getFileID(Spelled->location()));
- assert(FileIt != Files.end() && "file not tracked by token buffer");
-
- auto &File = FileIt->second;
- assert(File.SpelledTokens.data() <= Spelled &&
- Spelled < (File.SpelledTokens.data() + File.SpelledTokens.size()));
+ const auto &File = fileForSpelled(*Spelled);
unsigned SpelledIndex = Spelled - File.SpelledTokens.data();
auto M = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
@@ -412,14 +420,27 @@ TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
});
if (M == File.Mappings.end() || M->BeginSpelled != SpelledIndex)
return llvm::None;
+ return makeExpansion(File, *M);
+}
- Expansion E;
- E.Spelled = llvm::makeArrayRef(File.SpelledTokens.data() + M->BeginSpelled,
- File.SpelledTokens.data() + M->EndSpelled);
- E.Expanded = llvm::makeArrayRef(ExpandedTokens.data() + M->BeginExpanded,
- ExpandedTokens.data() + M->EndExpanded);
- return E;
+std::vector<TokenBuffer::Expansion> TokenBuffer::expansionsOverlapping(
+ llvm::ArrayRef<syntax::Token> Spelled) const {
+ if (Spelled.empty())
+ return {};
+ const auto &File = fileForSpelled(Spelled);
+
+ // Find the first overlapping range, and then copy until we stop overlapping.
+ unsigned SpelledBeginIndex = Spelled.begin() - File.SpelledTokens.data();
+ unsigned SpelledEndIndex = Spelled.end() - File.SpelledTokens.data();
+ auto M = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
+ return M.EndSpelled <= SpelledBeginIndex;
+ });
+ std::vector<TokenBuffer::Expansion> Expansions;
+ for (; M != File.Mappings.end() && M->BeginSpelled < SpelledEndIndex; ++M)
+ Expansions.push_back(makeExpansion(File, *M));
+ return Expansions;
}
+
llvm::ArrayRef<syntax::Token>
syntax::spelledTokensTouching(SourceLocation Loc,
llvm::ArrayRef<syntax::Token> Tokens) {
@@ -554,11 +575,11 @@ public:
// A's startpoint.
if (!Range.getBegin().isFileID()) {
Range.setBegin(SM.getExpansionLoc(Range.getBegin()));
- assert(Collector->Expansions.count(Range.getBegin().getRawEncoding()) &&
+ assert(Collector->Expansions.count(Range.getBegin()) &&
"Overlapping macros should have same expansion location");
}
- Collector->Expansions[Range.getBegin().getRawEncoding()] = Range.getEnd();
+ Collector->Expansions[Range.getBegin()] = Range.getEnd();
LastExpansionEnd = Range.getEnd();
}
// FIXME: handle directives like #pragma, #include, etc.
@@ -690,8 +711,8 @@ private:
// If we know mapping bounds at [NextSpelled, KnownEnd] (macro expansion)
// then we want to partition our (empty) mapping.
// [Start, NextSpelled) [NextSpelled, KnownEnd] (KnownEnd, Target)
- SourceLocation KnownEnd = CollectedExpansions.lookup(
- SpelledTokens[NextSpelled].location().getRawEncoding());
+ SourceLocation KnownEnd =
+ CollectedExpansions.lookup(SpelledTokens[NextSpelled].location());
if (KnownEnd.isValid()) {
FlushMapping(); // Emits [Start, NextSpelled)
while (NextSpelled < SpelledTokens.size() &&
@@ -728,7 +749,7 @@ private:
// We need no mapping for file tokens copied to the expanded stream.
} else {
// We found a new macro expansion. We should have its spelling bounds.
- auto End = CollectedExpansions.lookup(Expansion.getRawEncoding());
+ auto End = CollectedExpansions.lookup(Expansion);
assert(End.isValid() && "Macro expansion wasn't captured?");
// Mapping starts here...
diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp
index 37579e6145b6..07ee13e313f5 100644
--- a/clang/lib/Tooling/Syntax/Tree.cpp
+++ b/clang/lib/Tooling/Syntax/Tree.cpp
@@ -19,8 +19,8 @@ namespace {
static void traverse(const syntax::Node *N,
llvm::function_ref<void(const syntax::Node *)> Visit) {
if (auto *T = dyn_cast<syntax::Tree>(N)) {
- for (auto *C = T->firstChild(); C; C = C->nextSibling())
- traverse(C, Visit);
+ for (const syntax::Node &C : T->getChildren())
+ traverse(&C, Visit);
}
Visit(N);
}
@@ -33,14 +33,14 @@ static void traverse(syntax::Node *N,
} // namespace
syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
- TokenBuffer Tokens)
- : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {}
+ const TokenBuffer &Tokens)
+ : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(Tokens) {}
-const clang::syntax::TokenBuffer &syntax::Arena::tokenBuffer() const {
+const syntax::TokenBuffer &syntax::Arena::getTokenBuffer() const {
return Tokens;
}
-std::pair<FileID, llvm::ArrayRef<syntax::Token>>
+std::pair<FileID, ArrayRef<syntax::Token>>
syntax::Arena::lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Input) {
auto FID = SourceMgr.createFileID(std::move(Input));
auto It = ExtraTokens.try_emplace(FID, tokenize(FID, SourceMgr, LangOpts));
@@ -52,26 +52,47 @@ syntax::Leaf::Leaf(const syntax::Token *Tok) : Node(NodeKind::Leaf), Tok(Tok) {
assert(Tok != nullptr);
}
-bool syntax::Leaf::classof(const Node *N) {
- return N->kind() == NodeKind::Leaf;
-}
-
syntax::Node::Node(NodeKind Kind)
- : Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
- Role(0), Original(false), CanModify(false) {
+ : Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),
+ Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),
+ CanModify(false) {
this->setRole(NodeRole::Detached);
}
-bool syntax::Node::isDetached() const { return role() == NodeRole::Detached; }
+bool syntax::Node::isDetached() const {
+ return getRole() == NodeRole::Detached;
+}
void syntax::Node::setRole(NodeRole NR) {
this->Role = static_cast<unsigned>(NR);
}
-bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; }
+void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {
+ assert(Child->getRole() == NodeRole::Detached);
+ assert(Role != NodeRole::Detached);
+
+ Child->setRole(Role);
+ appendChildLowLevel(Child);
+}
+
+void syntax::Tree::appendChildLowLevel(Node *Child) {
+ assert(Child->Parent == nullptr);
+ assert(Child->NextSibling == nullptr);
+ assert(Child->PreviousSibling == nullptr);
+ assert(Child->getRole() != NodeRole::Detached);
+
+ Child->Parent = this;
+ if (this->LastChild) {
+ Child->PreviousSibling = this->LastChild;
+ this->LastChild->NextSibling = Child;
+ } else
+ this->FirstChild = Child;
+
+ this->LastChild = Child;
+}
void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
- assert(Child->role() == NodeRole::Detached);
+ assert(Child->getRole() == NodeRole::Detached);
assert(Role != NodeRole::Detached);
Child->setRole(Role);
@@ -81,135 +102,166 @@ void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
void syntax::Tree::prependChildLowLevel(Node *Child) {
assert(Child->Parent == nullptr);
assert(Child->NextSibling == nullptr);
- assert(Child->role() != NodeRole::Detached);
+ assert(Child->PreviousSibling == nullptr);
+ assert(Child->getRole() != NodeRole::Detached);
Child->Parent = this;
- Child->NextSibling = this->FirstChild;
+ if (this->FirstChild) {
+ Child->NextSibling = this->FirstChild;
+ this->FirstChild->PreviousSibling = Child;
+ } else
+ this->LastChild = Child;
+
this->FirstChild = Child;
}
-void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
+void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,
Node *New) {
- assert(!BeforeBegin || BeforeBegin->Parent == this);
+ assert((!Begin || Begin->Parent == this) &&
+ "`Begin` is not a child of `this`.");
+ assert((!End || End->Parent == this) && "`End` is not a child of `this`.");
+ assert(canModify() && "Cannot modify `this`.");
#ifndef NDEBUG
- for (auto *N = New; N; N = N->nextSibling()) {
+ for (auto *N = New; N; N = N->NextSibling) {
assert(N->Parent == nullptr);
- assert(N->role() != NodeRole::Detached && "Roles must be set");
+ assert(N->getRole() != NodeRole::Detached && "Roles must be set");
// FIXME: sanity-check the role.
}
+
+ auto Reachable = [](Node *From, Node *N) {
+ if (!N)
+ return true;
+ for (auto *It = From; It; It = It->NextSibling)
+ if (It == N)
+ return true;
+ return false;
+ };
+ assert(Reachable(FirstChild, Begin) && "`Begin` is not reachable.");
+ assert(Reachable(Begin, End) && "`End` is not after `Begin`.");
#endif
+ if (!New && Begin == End)
+ return;
+
+ // Mark modification.
+ for (auto *T = this; T && T->Original; T = T->Parent)
+ T->Original = false;
+
+ // Save the node before the range to be removed. Later we insert the `New`
+ // range after this node.
+ auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;
+
// Detach old nodes.
- for (auto *N = !BeforeBegin ? FirstChild : BeforeBegin->nextSibling();
- N != End;) {
+ for (auto *N = Begin; N != End;) {
auto *Next = N->NextSibling;
N->setRole(NodeRole::Detached);
N->Parent = nullptr;
N->NextSibling = nullptr;
+ N->PreviousSibling = nullptr;
if (N->Original)
- traverse(N, [&](Node *C) { C->Original = false; });
+ traverse(N, [](Node *C) { C->Original = false; });
N = Next;
}
- // Attach new nodes.
- if (BeforeBegin)
- BeforeBegin->NextSibling = New ? New : End;
- else
- FirstChild = New ? New : End;
+ // Attach new range.
+ auto *&NewFirst = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
+ auto *&NewLast = End ? End->PreviousSibling : LastChild;
- if (New) {
- auto *Last = New;
- for (auto *N = New; N != nullptr; N = N->nextSibling()) {
- Last = N;
- N->Parent = this;
- }
- Last->NextSibling = End;
+ if (!New) {
+ NewFirst = End;
+ NewLast = BeforeBegin;
+ return;
}
- // Mark the node as modified.
- for (auto *T = this; T && T->Original; T = T->Parent)
- T->Original = false;
+ New->PreviousSibling = BeforeBegin;
+ NewFirst = New;
+
+ Node *LastInNew;
+ for (auto *N = New; N != nullptr; N = N->NextSibling) {
+ LastInNew = N;
+ N->Parent = this;
+ }
+ LastInNew->NextSibling = End;
+ NewLast = LastInNew;
}
namespace {
-static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens,
- const SourceManager &SM) {
- assert(!Tokens.empty());
- bool First = true;
- for (const auto &T : Tokens) {
- if (!First)
- OS << " ";
- else
- First = false;
- // Handle 'eof' separately, calling text() on it produces an empty string.
- if (T.kind() == tok::eof) {
- OS << "<eof>";
- continue;
- }
- OS << T.text(SM);
- }
+static void dumpLeaf(raw_ostream &OS, const syntax::Leaf *L,
+ const SourceManager &SM) {
+ assert(L);
+ const auto *Token = L->getToken();
+ assert(Token);
+ // Handle 'eof' separately, calling text() on it produces an empty string.
+ if (Token->kind() == tok::eof)
+ OS << "<eof>";
+ else
+ OS << Token->text(SM);
}
-static void dumpTree(llvm::raw_ostream &OS, const syntax::Node *N,
- const syntax::Arena &A, std::vector<bool> IndentMask) {
- std::string Marks;
- if (!N->isOriginal())
- Marks += "M";
- if (N->role() == syntax::NodeRole::Detached)
- Marks += "*"; // FIXME: find a nice way to print other roles.
- if (!N->canModify())
- Marks += "I";
- if (!Marks.empty())
- OS << Marks << ": ";
+static void dumpNode(raw_ostream &OS, const syntax::Node *N,
+ const SourceManager &SM, std::vector<bool> IndentMask) {
+ auto DumpExtraInfo = [&OS](const syntax::Node *N) {
+ if (N->getRole() != syntax::NodeRole::Unknown)
+ OS << " " << N->getRole();
+ if (!N->isOriginal())
+ OS << " synthesized";
+ if (!N->canModify())
+ OS << " unmodifiable";
+ };
- if (auto *L = llvm::dyn_cast<syntax::Leaf>(N)) {
- dumpTokens(OS, *L->token(), A.sourceManager());
+ assert(N);
+ if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
+ OS << "'";
+ dumpLeaf(OS, L, SM);
+ OS << "'";
+ DumpExtraInfo(N);
OS << "\n";
return;
}
- auto *T = llvm::cast<syntax::Tree>(N);
- OS << T->kind() << "\n";
+ const auto *T = cast<syntax::Tree>(N);
+ OS << T->getKind();
+ DumpExtraInfo(N);
+ OS << "\n";
- for (auto It = T->firstChild(); It != nullptr; It = It->nextSibling()) {
+ for (const syntax::Node &It : T->getChildren()) {
for (bool Filled : IndentMask) {
if (Filled)
OS << "| ";
else
OS << " ";
}
- if (!It->nextSibling()) {
+ if (!It.getNextSibling()) {
OS << "`-";
IndentMask.push_back(false);
} else {
OS << "|-";
IndentMask.push_back(true);
}
- dumpTree(OS, It, A, IndentMask);
+ dumpNode(OS, &It, SM, IndentMask);
IndentMask.pop_back();
}
}
} // namespace
-std::string syntax::Node::dump(const Arena &A) const {
+std::string syntax::Node::dump(const SourceManager &SM) const {
std::string Str;
llvm::raw_string_ostream OS(Str);
- dumpTree(OS, this, A, /*IndentMask=*/{});
+ dumpNode(OS, this, SM, /*IndentMask=*/{});
return std::move(OS.str());
}
-std::string syntax::Node::dumpTokens(const Arena &A) const {
+std::string syntax::Node::dumpTokens(const SourceManager &SM) const {
std::string Storage;
llvm::raw_string_ostream OS(Storage);
traverse(this, [&](const syntax::Node *N) {
- auto *L = llvm::dyn_cast<syntax::Leaf>(N);
- if (!L)
- return;
- ::dumpTokens(OS, *L->token(), A.sourceManager());
- OS << " ";
+ if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
+ dumpLeaf(OS, L, SM);
+ OS << " ";
+ }
});
return OS.str();
}
@@ -217,19 +269,37 @@ std::string syntax::Node::dumpTokens(const Arena &A) const {
void syntax::Node::assertInvariants() const {
#ifndef NDEBUG
if (isDetached())
- assert(parent() == nullptr);
+ assert(getParent() == nullptr);
else
- assert(parent() != nullptr);
+ assert(getParent() != nullptr);
- auto *T = dyn_cast<Tree>(this);
+ const auto *T = dyn_cast<Tree>(this);
if (!T)
return;
- for (auto *C = T->firstChild(); C; C = C->nextSibling()) {
+ for (const Node &C : T->getChildren()) {
if (T->isOriginal())
- assert(C->isOriginal());
- assert(!C->isDetached());
- assert(C->parent() == T);
+ assert(C.isOriginal());
+ assert(!C.isDetached());
+ assert(C.getParent() == T);
+ const auto *Next = C.getNextSibling();
+ assert(!Next || &C == Next->getPreviousSibling());
+ if (!C.getNextSibling())
+ assert(&C == T->getLastChild() &&
+ "Last child is reachable by advancing from the first child.");
+ }
+
+ const auto *L = dyn_cast<List>(T);
+ if (!L)
+ return;
+ for (const Node &C : T->getChildren()) {
+ assert(C.getRole() == NodeRole::ListElement ||
+ C.getRole() == NodeRole::ListDelimiter);
+ if (C.getRole() == NodeRole::ListDelimiter) {
+ assert(isa<Leaf>(C));
+ assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind());
+ }
}
+
#endif
}
@@ -239,34 +309,162 @@ void syntax::Node::assertInvariantsRecursive() const {
#endif
}
-syntax::Leaf *syntax::Tree::firstLeaf() {
- auto *T = this;
- while (auto *C = T->firstChild()) {
- if (auto *L = dyn_cast<syntax::Leaf>(C))
+const syntax::Leaf *syntax::Tree::findFirstLeaf() const {
+ for (const Node &C : getChildren()) {
+ if (const auto *L = dyn_cast<syntax::Leaf>(&C))
+ return L;
+ if (const auto *L = cast<syntax::Tree>(C).findFirstLeaf())
return L;
- T = cast<syntax::Tree>(C);
}
return nullptr;
}
-syntax::Leaf *syntax::Tree::lastLeaf() {
- auto *T = this;
- while (auto *C = T->firstChild()) {
- // Find the last child.
- while (auto *Next = C->nextSibling())
- C = Next;
-
- if (auto *L = dyn_cast<syntax::Leaf>(C))
+const syntax::Leaf *syntax::Tree::findLastLeaf() const {
+ for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {
+ if (const auto *L = dyn_cast<syntax::Leaf>(C))
+ return L;
+ if (const auto *L = cast<syntax::Tree>(C)->findLastLeaf())
return L;
- T = cast<syntax::Tree>(C);
}
return nullptr;
}
-syntax::Node *syntax::Tree::findChild(NodeRole R) {
- for (auto *C = FirstChild; C; C = C->nextSibling()) {
- if (C->role() == R)
- return C;
+const syntax::Node *syntax::Tree::findChild(NodeRole R) const {
+ for (const Node &C : getChildren()) {
+ if (C.getRole() == R)
+ return &C;
}
return nullptr;
}
+
+std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>
+syntax::List::getElementsAsNodesAndDelimiters() {
+ if (!getFirstChild())
+ return {};
+
+ std::vector<syntax::List::ElementAndDelimiter<Node>> Children;
+ syntax::Node *ElementWithoutDelimiter = nullptr;
+ for (Node &C : getChildren()) {
+ switch (C.getRole()) {
+ case syntax::NodeRole::ListElement: {
+ if (ElementWithoutDelimiter) {
+ Children.push_back({ElementWithoutDelimiter, nullptr});
+ }
+ ElementWithoutDelimiter = &C;
+ break;
+ }
+ case syntax::NodeRole::ListDelimiter: {
+ Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(&C)});
+ ElementWithoutDelimiter = nullptr;
+ break;
+ }
+ default:
+ llvm_unreachable(
+ "A list can have only elements and delimiters as children.");
+ }
+ }
+
+ switch (getTerminationKind()) {
+ case syntax::List::TerminationKind::Separated: {
+ Children.push_back({ElementWithoutDelimiter, nullptr});
+ break;
+ }
+ case syntax::List::TerminationKind::Terminated:
+ case syntax::List::TerminationKind::MaybeTerminated: {
+ if (ElementWithoutDelimiter) {
+ Children.push_back({ElementWithoutDelimiter, nullptr});
+ }
+ break;
+ }
+ }
+
+ return Children;
+}
+
+// Almost the same implementation of `getElementsAsNodesAndDelimiters` but
+// ignoring delimiters
+std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {
+ if (!getFirstChild())
+ return {};
+
+ std::vector<syntax::Node *> Children;
+ syntax::Node *ElementWithoutDelimiter = nullptr;
+ for (Node &C : getChildren()) {
+ switch (C.getRole()) {
+ case syntax::NodeRole::ListElement: {
+ if (ElementWithoutDelimiter) {
+ Children.push_back(ElementWithoutDelimiter);
+ }
+ ElementWithoutDelimiter = &C;
+ break;
+ }
+ case syntax::NodeRole::ListDelimiter: {
+ Children.push_back(ElementWithoutDelimiter);
+ ElementWithoutDelimiter = nullptr;
+ break;
+ }
+ default:
+ llvm_unreachable("A list has only elements or delimiters.");
+ }
+ }
+
+ switch (getTerminationKind()) {
+ case syntax::List::TerminationKind::Separated: {
+ Children.push_back(ElementWithoutDelimiter);
+ break;
+ }
+ case syntax::List::TerminationKind::Terminated:
+ case syntax::List::TerminationKind::MaybeTerminated: {
+ if (ElementWithoutDelimiter) {
+ Children.push_back(ElementWithoutDelimiter);
+ }
+ break;
+ }
+ }
+
+ return Children;
+}
+
+clang::tok::TokenKind syntax::List::getDelimiterTokenKind() const {
+ switch (this->getKind()) {
+ case NodeKind::NestedNameSpecifier:
+ return clang::tok::coloncolon;
+ case NodeKind::CallArguments:
+ case NodeKind::ParameterDeclarationList:
+ case NodeKind::DeclaratorList:
+ return clang::tok::comma;
+ default:
+ llvm_unreachable("This is not a subclass of List, thus "
+ "getDelimiterTokenKind() cannot be called");
+ }
+}
+
+syntax::List::TerminationKind syntax::List::getTerminationKind() const {
+ switch (this->getKind()) {
+ case NodeKind::NestedNameSpecifier:
+ return TerminationKind::Terminated;
+ case NodeKind::CallArguments:
+ case NodeKind::ParameterDeclarationList:
+ case NodeKind::DeclaratorList:
+ return TerminationKind::Separated;
+ default:
+ llvm_unreachable("This is not a subclass of List, thus "
+ "getTerminationKind() cannot be called");
+ }
+}
+
+bool syntax::List::canBeEmpty() const {
+ switch (this->getKind()) {
+ case NodeKind::NestedNameSpecifier:
+ return false;
+ case NodeKind::CallArguments:
+ return true;
+ case NodeKind::ParameterDeclarationList:
+ return true;
+ case NodeKind::DeclaratorList:
+ return true;
+ default:
+ llvm_unreachable("This is not a subclass of List, thus canBeEmpty() "
+ "cannot be called");
+ }
+}