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/BuildTree.cpp | |
| parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) | |
Diffstat (limited to 'clang/lib/Tooling/Syntax/BuildTree.cpp')
| -rw-r--r-- | clang/lib/Tooling/Syntax/BuildTree.cpp | 817 |
1 files changed, 592 insertions, 225 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(); } |
