aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Tooling/Syntax/BuildTree.cpp
diff options
context:
space:
mode:
authorEduardo Caldas <ecaldas@google.com>2020-09-28 09:33:11 +0000
committerEduardo Caldas <ecaldas@google.com>2020-10-01 13:56:31 +0000
commit5011d43108d1de30a056d66e73fa19062e0e84b7 (patch)
treef29368155c36ee8b4c6bd62226dd3129757e7a9a /clang/lib/Tooling/Syntax/BuildTree.cpp
parent79fbcbff41734e3d07e6200d33c3e40732dfae6a (diff)
downloadllvm-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.cpp69
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;