Skip to content
Snippets Groups Projects
Commit f19ada14 authored by Alex Lorenz's avatar Alex Lorenz
Browse files

Allow StmtPrinter to supress implicit 'this' and 'self' base expressions

This will be useful for certain refactoring actions.

rdar://34202062


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316631 91177308-0d34-0410-b5e6-96231b3b80d8
parent 2150c7da
No related branches found
No related tags found
No related merge requests found
......@@ -51,7 +51,7 @@ struct PrintingPolicy {
TerseOutput(false), PolishForDeclaration(false),
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
IncludeNewlines(true), MSVCFormatting(false),
ConstantsAsWritten(false) { }
ConstantsAsWritten(false), SuppressImplicitBase(false) { }
/// \brief Adjust this printing policy for cases where it's known that
/// we're printing C++ code (for instance, if AST dumping reaches a
......@@ -218,7 +218,10 @@ struct PrintingPolicy {
/// 0x10
/// 2.5e3
/// \endcode
bool ConstantsAsWritten;
bool ConstantsAsWritten : 1;
/// \brief When true, don't print the implicit 'self' or 'this' expressions.
bool SuppressImplicitBase : 1;
};
} // end namespace clang
......
......@@ -1346,10 +1346,25 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
OS, Node->template_arguments(), Policy);
}
static bool isImplicitSelf(const Expr *E) {
if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
if (const ImplicitParamDecl *PD =
dyn_cast<ImplicitParamDecl>(DRE->getDecl())) {
if (PD->getParameterKind() == ImplicitParamDecl::ObjCSelf &&
DRE->getLocStart().isInvalid())
return true;
}
}
return false;
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
if (Node->getBase()) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
if (!Policy.SuppressImplicitBase ||
!isImplicitSelf(Node->getBase()->IgnoreImpCasts())) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
}
OS << *Node->getDecl();
}
......@@ -1670,16 +1685,25 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
PrintCallArgs(Call);
OS << ")";
}
static bool isImplicitThis(const Expr *E) {
if (const auto *TE = dyn_cast<CXXThisExpr>(E))
return TE->isImplicit();
return false;
}
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
// FIXME: Suppress printing implicit bases (like "this")
PrintExpr(Node->getBase());
if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) {
PrintExpr(Node->getBase());
MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
FieldDecl *ParentDecl = ParentMember
? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : nullptr;
MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
FieldDecl *ParentDecl =
ParentMember ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl())
: nullptr;
if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
OS << (Node->isArrow() ? "->" : ".");
if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
OS << (Node->isArrow() ? "->" : ".");
}
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
if (FD->isAnonymousStructOrUnion())
......
......@@ -31,18 +31,26 @@ using namespace tooling;
namespace {
void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) {
using PolicyAdjusterType =
Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>;
void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S,
PolicyAdjusterType PolicyAdjuster) {
assert(S != nullptr && "Expected non-null Stmt");
PrintingPolicy Policy = Context->getPrintingPolicy();
if (PolicyAdjuster)
(*PolicyAdjuster)(Policy);
S->printPretty(Out, /*Helper*/ nullptr, Policy);
}
class PrintMatch : public MatchFinder::MatchCallback {
SmallString<1024> Printed;
unsigned NumFoundStmts;
PolicyAdjusterType PolicyAdjuster;
public:
PrintMatch() : NumFoundStmts(0) {}
PrintMatch(PolicyAdjusterType PolicyAdjuster)
: NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
void run(const MatchFinder::MatchResult &Result) override {
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
......@@ -53,7 +61,7 @@ public:
return;
llvm::raw_svector_ostream Out(Printed);
PrintStmt(Out, Result.Context, S);
PrintStmt(Out, Result.Context, S, PolicyAdjuster);
}
StringRef getPrinted() const {
......@@ -68,9 +76,10 @@ public:
template <typename T>
::testing::AssertionResult
PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
const T &NodeMatch, StringRef ExpectedPrinted) {
const T &NodeMatch, StringRef ExpectedPrinted,
PolicyAdjusterType PolicyAdjuster = None) {
PrintMatch Printer;
PrintMatch Printer(PolicyAdjuster);
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
std::unique_ptr<FrontendActionFactory> Factory(
......@@ -122,11 +131,13 @@ PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
::testing::AssertionResult
PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
StringRef ExpectedPrinted) {
StringRef ExpectedPrinted,
PolicyAdjusterType PolicyAdjuster = None) {
std::vector<std::string> Args;
Args.push_back("-std=c++11");
Args.push_back("-Wno-unused-value");
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
PolicyAdjuster);
}
::testing::AssertionResult PrintedStmtMSMatches(
......@@ -146,6 +157,17 @@ PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
ExpectedPrinted);
}
::testing::AssertionResult
PrintedStmtObjCMatches(StringRef Code, const StatementMatcher &NodeMatch,
StringRef ExpectedPrinted,
PolicyAdjusterType PolicyAdjuster = None) {
std::vector<std::string> Args;
Args.push_back("-ObjC");
Args.push_back("-fobjc-runtime=macosx-10.12.0");
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
PolicyAdjuster);
}
} // unnamed namespace
TEST(StmtPrinter, TestIntegerLiteral) {
......@@ -214,3 +236,41 @@ TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
"(a & b)"));
// WRONG; Should be: (a & b).operator void *()
}
TEST(StmtPrinter, TestNoImplicitBases) {
const char *CPPSource = R"(
class A {
int field;
int member() { return field; }
};
)";
// No implicit 'this'.
ASSERT_TRUE(PrintedStmtCXX11Matches(
CPPSource, memberExpr(anything()).bind("id"), "field",
PolicyAdjusterType(
[](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
// Print implicit 'this'.
ASSERT_TRUE(PrintedStmtCXX11Matches(
CPPSource, memberExpr(anything()).bind("id"), "this->field"));
const char *ObjCSource = R"(
@interface I {
int ivar;
}
@end
@implementation I
- (int) method {
return ivar;
}
@end
)";
// No implicit 'self'.
ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
"return ivar;\n",
PolicyAdjusterType([](PrintingPolicy &PP) {
PP.SuppressImplicitBase = true;
})));
// Print implicit 'self'.
ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
"return self->ivar;\n"));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment