From: Alex Lorenz Date: Thu, 26 Oct 2017 00:56:54 +0000 (+0000) Subject: Allow StmtPrinter to supress implicit 'this' and 'self' base expressions X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f757961c0f79de81d9ae80a3cc64ed7a932a8b5f;p=platform%2Fupstream%2Fllvm.git Allow StmtPrinter to supress implicit 'this' and 'self' base expressions This will be useful for certain refactoring actions. rdar://34202062 llvm-svn: 316631 --- diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 54fe398..953ecad 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -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 diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 9cbd1ef..371d3e1 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -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(E)) { + if (const ImplicitParamDecl *PD = + dyn_cast(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(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(Node->getBase()); - FieldDecl *ParentDecl = ParentMember - ? dyn_cast(ParentMember->getMemberDecl()) : nullptr; + MemberExpr *ParentMember = dyn_cast(Node->getBase()); + FieldDecl *ParentDecl = + ParentMember ? dyn_cast(ParentMember->getMemberDecl()) + : nullptr; - if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion()) - OS << (Node->isArrow() ? "->" : "."); + if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion()) + OS << (Node->isArrow() ? "->" : "."); + } if (FieldDecl *FD = dyn_cast(Node->getMemberDecl())) if (FD->isAnonymousStructOrUnion()) diff --git a/clang/unittests/AST/StmtPrinterTest.cpp b/clang/unittests/AST/StmtPrinterTest.cpp index 12b2032..a064440 100644 --- a/clang/unittests/AST/StmtPrinterTest.cpp +++ b/clang/unittests/AST/StmtPrinterTest.cpp @@ -31,18 +31,26 @@ using namespace tooling; namespace { -void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) { +using PolicyAdjusterType = + Optional>; + +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("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 ::testing::AssertionResult PrintedStmtMatches(StringRef Code, const std::vector &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 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 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 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")); +}