eduucaldas created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
eduucaldas requested review of this revision.
Example of such refactoring:
Customer* C;
getCustumer(C);
Customer C = getCustumer();
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D89794
Files:
clang/include/clang/Tooling/Syntax/Mutations.h
clang/lib/Tooling/Syntax/Mutations.cpp
Index: clang/lib/Tooling/Syntax/Mutations.cpp
===
--- clang/lib/Tooling/Syntax/Mutations.cpp
+++ clang/lib/Tooling/Syntax/Mutations.cpp
@@ -85,6 +85,92 @@
P->assertInvariants();
N->assertInvariants();
}
+
+ static void
+ replaceChildRange(syntax::Tree *Parent, syntax::Node *BeforeBegin,
+syntax::Node *End,
+ArrayRef> NewRange) {
+if (NewRange.empty())
+ return Parent->replaceChildRangeLowLevel(BeforeBegin, End, nullptr);
+
+for (const auto : NewRange)
+ NodeAndRole.first->setRole(NodeAndRole.second);
+
+for (auto It = NewRange.begin(), EndIt = std::prev(NewRange.end());
+ It != EndIt; ++It) {
+ auto *Node = It->first;
+ auto *Next = std::next(It)->first;
+ Node->NextSibling = Next;
+}
+
+Parent->replaceChildRangeLowLevel(BeforeBegin, End, NewRange.front().first);
+ }
+
+ /// Removes all the `Node`s between the iterators `BeforeBegin` and `End`. For
+ /// separated lists, if we remove the last element we may need to remove the
+ /// delimiter before it, in order to keep it a separated list.
+ static void removeElementAndDelimiterRange(
+ List::ElementAndDelimiterIterator BeforeBegin,
+ List::ElementAndDelimiterIterator End) {
+auto *EndNode = []() -> Node * {
+ if (End.isEnd())
+return nullptr;
+ if ((*End).element)
+return (*End).element;
+ return (*End).delimiter;
+}();
+auto *Parent = End.getParent();
+Node *BeforeBeginNode;
+if (End.isEnd() &&
+Parent->getTerminationKind() == List::TerminationKind::Separated) {
+ // In this case we also remove the delimiter before the last element of
+ // the list, if it exists.
+ if (BeforeBegin.isBeforeBegin())
+BeforeBeginNode = nullptr;
+ else if ((*BeforeBegin).element)
+BeforeBeginNode = (*BeforeBegin).element;
+ else if ((*BeforeBegin).delimiter)
+BeforeBeginNode = findPrevious((*BeforeBegin).delimiter);
+ else
+// `BeforeBegin` = (null, null) and thus we are in the last element of
+// the list. Nothing will be removed.
+return;
+} else
+ BeforeBeginNode = []() -> Node * {
+if (BeforeBegin.isBeforeBegin())
+ return nullptr;
+if ((*BeforeBegin).delimiter)
+ return (*BeforeBegin).delimiter;
+if ((*BeforeBegin).element)
+ return (*BeforeBegin).element;
+llvm_unreachable("(null, null) can only appear in the end of a "
+ "separated range, and this is not possible here");
+ }();
+
+Parent->replaceChildRangeLowLevel(BeforeBeginNode, EndNode, nullptr);
+ }
+
+ static Node *extractLastElementAndDelimiter(List *Parent) {
+auto Prev = [](List::ElementAndDelimiterIterator EDI,
+ unsigned i = 1) {
+ auto Previous = EDI.getParent()->getElementAndDelimiterBeforeBegin();
+ auto It = Previous;
+ for (unsigned j = 0; j < i; ++j)
+++It;
+ for (; It != EDI; ++It)
+++Previous;
+
+ return Previous;
+};
+if (Parent->getElementAndDelimiterBegin() ==
+Parent->getElementAndDelimiterEnd())
+ return nullptr;
+auto BeforeLast = Prev(Parent->getElementAndDelimiterEnd(), 2);
+auto Last = std::next(BeforeLast);
+removeElementAndDelimiterRange(BeforeLast,
+ Parent->getElementAndDelimiterEnd());
+return (*Last).element;
+ }
};
void syntax::removeStatement(syntax::Arena , syntax::Statement *S) {
@@ -102,3 +188,39 @@
MutationsImpl::replace(S, createEmptyStatement(A));
}
+
+void syntax::replaceOutputParameterWithReturnValue(syntax::Arena ,
+ syntax::CallExpression *CE) {
+ assert(CE);
+ assert(CE->canModify());
+ assert(CE->getParent());
+
+ // Extract Output Parameter
+ auto *OutParam =
+ MutationsImpl::extractLastElementAndDelimiter(CE->getArguments());
+
+ // Create pointer dereference with outParam
+ auto *DerefOutParam =
+ createTree(A,
+ {{createLeaf(A, tok::star), NodeRole::OperatorToken},
+ {OutParam, NodeRole::Operand}},
+ NodeKind::PrefixUnaryOperatorExpression);
+
+ // f(); -> *outParam = f();
+ // TODO: How to improve this: Add parent to AddAfter. Or `NodeIterator`, with
+ // a pointer to Parent when it's a sentinel.
+ auto *Parent = CE->getParent();
+ auto *BeforeBegin = findPrevious(CE);
+