[refactor][selection] canonicalize decl ref callee to the call expr
We would like to extract the full call when just the callee function is
selected
llvm-svn: 318215
diff --git a/clang/lib/Tooling/Refactoring/ASTSelection.cpp b/clang/lib/Tooling/Refactoring/ASTSelection.cpp
index ae8a3cb..7123fc3 100644
--- a/clang/lib/Tooling/Refactoring/ASTSelection.cpp
+++ b/clang/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -259,6 +259,35 @@
/// when it makes sense to do so.
void canonicalize();
};
+
+enum SelectionCanonicalizationAction { KeepSelection, SelectParent };
+
+/// Returns the canonicalization action which should be applied to the
+/// selected statement.
+SelectionCanonicalizationAction
+getSelectionCanonizalizationAction(const Stmt *S, const Stmt *Parent) {
+ // Select the parent expression when:
+ // - The string literal in ObjC string literal is selected, e.g.:
+ // @"test" becomes @"test"
+ // ~~~~~~ ~~~~~~~
+ if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent))
+ return SelectParent;
+ // The entire call should be selected when just the member expression
+ // that refers to the method or the decl ref that refers to the function
+ // is selected.
+ // f.call(args) becomes f.call(args)
+ // ~~~~ ~~~~~~~~~~~~
+ // func(args) becomes func(args)
+ // ~~~~ ~~~~~~~~~~
+ else if (const auto *CE = dyn_cast<CallExpr>(Parent)) {
+ if ((isa<MemberExpr>(S) || isa<DeclRefExpr>(S)) &&
+ CE->getCallee()->IgnoreImpCasts() == S)
+ return SelectParent;
+ }
+ // FIXME: Syntactic form -> Entire pseudo-object expr.
+ return KeepSelection;
+}
+
} // end anonymous namespace
void SelectedNodeWithParents::canonicalize() {
@@ -267,21 +296,27 @@
const Stmt *Parent = Parents[Parents.size() - 1].get().Node.get<Stmt>();
if (!Parent)
return;
- // Select the parent expression when:
- // - The string literal in ObjC string literal is selected, e.g.:
- // @"test" becomes @"test"
- // ~~~~~~ ~~~~~~~
- if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent))
- Node = Parents.pop_back_val();
- // The entire call should be selected when just the member expression
- // that refers to the method is selected.
- // f.call(args) becomes f.call(args)
- // ~~~~ ~~~~~~~~~~~~
- else if (isa<MemberExpr>(S) && isa<CXXMemberCallExpr>(Parent) &&
- cast<CXXMemberCallExpr>(Parent)->getCallee() == S)
- Node = Parents.pop_back_val();
- // FIXME: Syntactic form -> Entire pseudo-object expr.
- // FIXME: Callee -> Call.
+
+ // Look through the implicit casts in the parents.
+ unsigned ParentIndex = 1;
+ for (; (ParentIndex + 1) <= Parents.size() && isa<ImplicitCastExpr>(Parent);
+ ++ParentIndex) {
+ const Stmt *NewParent =
+ Parents[Parents.size() - ParentIndex - 1].get().Node.get<Stmt>();
+ if (!NewParent)
+ break;
+ Parent = NewParent;
+ }
+
+ switch (getSelectionCanonizalizationAction(S, Parent)) {
+ case SelectParent:
+ Node = Parents[Parents.size() - ParentIndex];
+ for (; ParentIndex != 0; --ParentIndex)
+ Parents.pop_back();
+ break;
+ case KeepSelection:
+ break;
+ }
}
/// Finds the set of bottom-most selected AST nodes that are in the selection