[refactor][selection] canonicalize member expr callee to the full

member call expression

We would like to extract the full call when just the callee is selected.

llvm-svn: 318205
This commit is contained in:
Alex Lorenz 2017-11-14 22:06:55 +00:00
parent 383fbd050c
commit f64d0a4d00
2 changed files with 64 additions and 1 deletions

View File

@ -115,6 +115,11 @@ public:
return true;
if (auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
return TraverseOpaqueValueExpr(Opaque);
// Avoid selecting implicit 'this' expressions.
if (auto *TE = dyn_cast<CXXThisExpr>(S)) {
if (TE->isImplicit())
return true;
}
// FIXME (Alex Lorenz): Improve handling for macro locations.
SourceSelectionKind SelectionKind =
selectionKindFor(CharSourceRange::getTokenRange(S->getSourceRange()));
@ -268,9 +273,15 @@ void SelectedNodeWithParents::canonicalize() {
// ~~~~~~ ~~~~~~~
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.
// FIXME: Callee member expr -> Call.
}
/// Finds the set of bottom-most selected AST nodes that are in the selection

View File

@ -1004,4 +1004,56 @@ void foo() {
SelectionFinderVisitor::Lang_OBJC);
}
TEST(ASTSelectionFinder, CanonicalizeMemberCalleeToCall) {
StringRef Source = R"(
class AClass { public:
void method();
int afield;
void selectWholeCallWhenJustMethodSelected(int &i) {
method();
}
};
void selectWholeCallWhenJustMethodSelected() {
AClass a;
a.method();
}
void dontSelectArgument(AClass &a) {
a.selectWholeCallWhenJustMethodSelected(a.afield);
}
)";
// Just 'method' with implicit 'this':
findSelectedASTNodesWithRange(
Source, {6, 5}, FileRange{{6, 5}, {6, 11}},
[](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
EXPECT_TRUE(Node);
Optional<CodeRangeASTSelection> SelectedCode =
CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
EXPECT_TRUE(SelectedCode);
EXPECT_EQ(SelectedCode->size(), 1u);
EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
});
// Just 'method':
findSelectedASTNodesWithRange(
Source, {11, 5}, FileRange{{11, 5}, {11, 11}},
[](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
EXPECT_TRUE(Node);
Optional<CodeRangeASTSelection> SelectedCode =
CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
EXPECT_TRUE(SelectedCode);
EXPECT_EQ(SelectedCode->size(), 1u);
EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
});
// Just 'afield', which should not select the call.
findSelectedASTNodesWithRange(
Source, {14, 5}, FileRange{{14, 45}, {14, 51}},
[](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
EXPECT_TRUE(Node);
Optional<CodeRangeASTSelection> SelectedCode =
CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
EXPECT_TRUE(SelectedCode);
EXPECT_EQ(SelectedCode->size(), 1u);
EXPECT_FALSE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
});
}
} // end anonymous namespace