diff options
author | Eduardo Caldas <ecaldas@google.com> | 2020-09-28 09:33:11 +0000 |
---|---|---|
committer | Eduardo Caldas <ecaldas@google.com> | 2020-10-01 13:56:31 +0000 |
commit | 5011d43108d1de30a056d66e73fa19062e0e84b7 (patch) | |
tree | f29368155c36ee8b4c6bd62226dd3129757e7a9a /clang/lib/Tooling/Syntax/BuildTree.cpp | |
parent | 79fbcbff41734e3d07e6200d33c3e40732dfae6a (diff) | |
download | llvm-5011d43108d1de30a056d66e73fa19062e0e84b7.zip llvm-5011d43108d1de30a056d66e73fa19062e0e84b7.tar.gz llvm-5011d43108d1de30a056d66e73fa19062e0e84b7.tar.bz2 |
Migrate Declarators to use the List API
After this change all nodes that have a delimited-list are using the
`List` API.
Implementation details:
Let's look at a declaration with multiple declarators:
`int a, b;`
To generate a declarator list node we need to have the range of
declarators: `a, b`:
However, the `ClangAST` actually stores them as separate declarations:
`int a ;`
`int b;`
We solve that by appropriately marking the declarators on each separate
declaration in the `ClangAST` and then for the final declarator `int
b`, shrinking its range to fit to the already marked declarators.
Differential Revision: https://reviews.llvm.org/D88403
Diffstat (limited to 'clang/lib/Tooling/Syntax/BuildTree.cpp')
-rw-r--r-- | clang/lib/Tooling/Syntax/BuildTree.cpp | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 4d36509..e1ed55f 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -397,6 +397,17 @@ public: 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); @@ -579,6 +590,35 @@ private: 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, ArrayRef<syntax::Token> Tokens, syntax::Tree *Node) { @@ -1513,14 +1553,31 @@ private: // 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::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; |