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();
}
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())
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");
return;
llvm::raw_svector_ostream Out(Printed);
- PrintStmt(Out, Result.Context, S);
+ PrintStmt(Out, Result.Context, S, PolicyAdjuster);
}
StringRef getPrinted() const {
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(
::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(
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) {
"(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"));
+}