diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
| commit | b60736ec1405bb0a8dd40989f67ef4c93da068ab (patch) | |
| tree | 5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /clang/lib/Tooling/Syntax | |
| parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) | |
Diffstat (limited to 'clang/lib/Tooling/Syntax')
| -rw-r--r-- | clang/lib/Tooling/Syntax/BuildTree.cpp | 817 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/ComputeReplacements.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/Mutations.cpp | 36 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/Nodes.cpp | 604 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/Synthesis.cpp | 224 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/Tokens.cpp | 89 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/Tree.cpp | 410 |
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"); + } +} |
