forked from OSchip/llvm-project
Allow StmtPrinter to supress implicit 'this' and 'self' base expressions
This will be useful for certain refactoring actions. rdar://34202062 llvm-svn: 316631
This commit is contained in:
parent
5adb96cc92
commit
f757961c0f
|
@ -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"));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue