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),
|
TerseOutput(false), PolishForDeclaration(false),
|
||||||
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
|
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
|
||||||
IncludeNewlines(true), MSVCFormatting(false),
|
IncludeNewlines(true), MSVCFormatting(false),
|
||||||
ConstantsAsWritten(false) { }
|
ConstantsAsWritten(false), SuppressImplicitBase(false) { }
|
||||||
|
|
||||||
/// \brief Adjust this printing policy for cases where it's known that
|
/// \brief Adjust this printing policy for cases where it's known that
|
||||||
/// we're printing C++ code (for instance, if AST dumping reaches a
|
/// we're printing C++ code (for instance, if AST dumping reaches a
|
||||||
|
@ -218,7 +218,10 @@ struct PrintingPolicy {
|
||||||
/// 0x10
|
/// 0x10
|
||||||
/// 2.5e3
|
/// 2.5e3
|
||||||
/// \endcode
|
/// \endcode
|
||||||
bool ConstantsAsWritten;
|
bool ConstantsAsWritten : 1;
|
||||||
|
|
||||||
|
/// \brief When true, don't print the implicit 'self' or 'this' expressions.
|
||||||
|
bool SuppressImplicitBase : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
|
@ -1346,10 +1346,25 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
|
||||||
OS, Node->template_arguments(), Policy);
|
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) {
|
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
|
||||||
if (Node->getBase()) {
|
if (Node->getBase()) {
|
||||||
PrintExpr(Node->getBase());
|
if (!Policy.SuppressImplicitBase ||
|
||||||
OS << (Node->isArrow() ? "->" : ".");
|
!isImplicitSelf(Node->getBase()->IgnoreImpCasts())) {
|
||||||
|
PrintExpr(Node->getBase());
|
||||||
|
OS << (Node->isArrow() ? "->" : ".");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OS << *Node->getDecl();
|
OS << *Node->getDecl();
|
||||||
}
|
}
|
||||||
|
@ -1670,16 +1685,25 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
|
||||||
PrintCallArgs(Call);
|
PrintCallArgs(Call);
|
||||||
OS << ")";
|
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) {
|
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
|
||||||
// FIXME: Suppress printing implicit bases (like "this")
|
if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) {
|
||||||
PrintExpr(Node->getBase());
|
PrintExpr(Node->getBase());
|
||||||
|
|
||||||
MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
|
MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
|
||||||
FieldDecl *ParentDecl = ParentMember
|
FieldDecl *ParentDecl =
|
||||||
? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : nullptr;
|
ParentMember ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl())
|
||||||
|
: nullptr;
|
||||||
|
|
||||||
if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
|
if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
|
||||||
OS << (Node->isArrow() ? "->" : ".");
|
OS << (Node->isArrow() ? "->" : ".");
|
||||||
|
}
|
||||||
|
|
||||||
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
|
||||||
if (FD->isAnonymousStructOrUnion())
|
if (FD->isAnonymousStructOrUnion())
|
||||||
|
|
|
@ -31,18 +31,26 @@ using namespace tooling;
|
||||||
|
|
||||||
namespace {
|
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");
|
assert(S != nullptr && "Expected non-null Stmt");
|
||||||
PrintingPolicy Policy = Context->getPrintingPolicy();
|
PrintingPolicy Policy = Context->getPrintingPolicy();
|
||||||
|
if (PolicyAdjuster)
|
||||||
|
(*PolicyAdjuster)(Policy);
|
||||||
S->printPretty(Out, /*Helper*/ nullptr, Policy);
|
S->printPretty(Out, /*Helper*/ nullptr, Policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PrintMatch : public MatchFinder::MatchCallback {
|
class PrintMatch : public MatchFinder::MatchCallback {
|
||||||
SmallString<1024> Printed;
|
SmallString<1024> Printed;
|
||||||
unsigned NumFoundStmts;
|
unsigned NumFoundStmts;
|
||||||
|
PolicyAdjusterType PolicyAdjuster;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrintMatch() : NumFoundStmts(0) {}
|
PrintMatch(PolicyAdjusterType PolicyAdjuster)
|
||||||
|
: NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
|
||||||
|
|
||||||
void run(const MatchFinder::MatchResult &Result) override {
|
void run(const MatchFinder::MatchResult &Result) override {
|
||||||
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
|
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
|
||||||
|
@ -53,7 +61,7 @@ public:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
llvm::raw_svector_ostream Out(Printed);
|
llvm::raw_svector_ostream Out(Printed);
|
||||||
PrintStmt(Out, Result.Context, S);
|
PrintStmt(Out, Result.Context, S, PolicyAdjuster);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef getPrinted() const {
|
StringRef getPrinted() const {
|
||||||
|
@ -68,9 +76,10 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
::testing::AssertionResult
|
::testing::AssertionResult
|
||||||
PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
|
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;
|
MatchFinder Finder;
|
||||||
Finder.addMatcher(NodeMatch, &Printer);
|
Finder.addMatcher(NodeMatch, &Printer);
|
||||||
std::unique_ptr<FrontendActionFactory> Factory(
|
std::unique_ptr<FrontendActionFactory> Factory(
|
||||||
|
@ -122,11 +131,13 @@ PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
|
||||||
|
|
||||||
::testing::AssertionResult
|
::testing::AssertionResult
|
||||||
PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
|
PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
|
||||||
StringRef ExpectedPrinted) {
|
StringRef ExpectedPrinted,
|
||||||
|
PolicyAdjusterType PolicyAdjuster = None) {
|
||||||
std::vector<std::string> Args;
|
std::vector<std::string> Args;
|
||||||
Args.push_back("-std=c++11");
|
Args.push_back("-std=c++11");
|
||||||
Args.push_back("-Wno-unused-value");
|
Args.push_back("-Wno-unused-value");
|
||||||
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
|
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
|
||||||
|
PolicyAdjuster);
|
||||||
}
|
}
|
||||||
|
|
||||||
::testing::AssertionResult PrintedStmtMSMatches(
|
::testing::AssertionResult PrintedStmtMSMatches(
|
||||||
|
@ -146,6 +157,17 @@ PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
|
||||||
ExpectedPrinted);
|
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
|
} // unnamed namespace
|
||||||
|
|
||||||
TEST(StmtPrinter, TestIntegerLiteral) {
|
TEST(StmtPrinter, TestIntegerLiteral) {
|
||||||
|
@ -214,3 +236,41 @@ TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
|
||||||
"(a & b)"));
|
"(a & b)"));
|
||||||
// WRONG; Should be: (a & b).operator void *()
|
// 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