diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2017-05-19 23:51:46 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2017-05-19 23:57:03 +0200 |
commit | 8b1fcedcd10366523967ebcbd463b2c0c6b5b17a (patch) | |
tree | 094af692230758812f3deb2828b0d1a5e22e4cb0 /compilerplugins/clang/compat.hxx | |
parent | a9a5fc3708406561399153d0bf44d8c323c9263e (diff) |
...and re-eanble loplugin:stringcopy again
<http://reviews.llvm.org/D22128> "Make CastExpr::getSubExprAsWritten look
through implicit temporary under CK_ConstructorConversion" was biting me again.
(I had originally developed loplugin:stringcopy against a Clang build that
includes my local fix for that issue. I really need to see to get that resolved
upstream...)
(And while 957874168491f4b030fda85c65dd969aae82a670 "loplugin:stringcopy" was
actually a false positive, it doesn't hurt either, so just keep it.)
Change-Id: I726956adfbe67681005173cfdfed2e4b4cd6253d
Diffstat (limited to 'compilerplugins/clang/compat.hxx')
-rw-r--r-- | compilerplugins/clang/compat.hxx | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/compilerplugins/clang/compat.hxx b/compilerplugins/clang/compat.hxx index 28dbeec71e20..a493cdc7b209 100644 --- a/compilerplugins/clang/compat.hxx +++ b/compilerplugins/clang/compat.hxx @@ -17,6 +17,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticIDs.h" @@ -244,6 +245,78 @@ inline bool isStdNamespace(clang::DeclContext const & context) { #endif } +// Work around <http://reviews.llvm.org/D22128>: +// +// SfxErrorHandler::GetClassString (svtools/source/misc/ehdl.cxx): +// +// ErrorResource_Impl aEr(aId, (sal_uInt16)lClassId); +// if(aEr) +// { +// rStr = static_cast<ResString>(aEr).GetString(); +// } +// +// expr->dump(): +// CXXStaticCastExpr 0x2b74e8e657b8 'class ResString' static_cast<class ResString> <ConstructorConversion> +// `-CXXBindTemporaryExpr 0x2b74e8e65798 'class ResString' (CXXTemporary 0x2b74e8e65790) +// `-CXXConstructExpr 0x2b74e8e65758 'class ResString' 'void (class ResString &&) noexcept(false)' elidable +// `-MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue +// `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718) +// `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion> +// `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString' +// `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00 +// `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl' +// expr->getSubExprAsWritten()->dump(): +// MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue +// `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718) +// `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion> +// `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString' +// `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00 +// `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl' +// +// Copies code from Clang's lib/AST/Expr.cpp: +namespace detail { + inline clang::Expr *skipImplicitTemporary(clang::Expr *expr) { + // Skip through reference binding to temporary. + if (clang::MaterializeTemporaryExpr *Materialize + = clang::dyn_cast<clang::MaterializeTemporaryExpr>(expr)) + expr = Materialize->GetTemporaryExpr(); + + // Skip any temporary bindings; they're implicit. + if (clang::CXXBindTemporaryExpr *Binder = clang::dyn_cast<clang::CXXBindTemporaryExpr>(expr)) + expr = Binder->getSubExpr(); + + return expr; + } +} +inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) { + clang::Expr *SubExpr = nullptr; + clang::CastExpr *E = This; + do { + SubExpr = detail::skipImplicitTemporary(E->getSubExpr()); + + // Conversions by constructor and conversion functions have a + // subexpression describing the call; strip it off. + if (E->getCastKind() == clang::CK_ConstructorConversion) + SubExpr = + detail::skipImplicitTemporary(clang::cast<clang::CXXConstructExpr>(SubExpr)->getArg(0)); + else if (E->getCastKind() == clang::CK_UserDefinedConversion) { + assert((clang::isa<clang::CXXMemberCallExpr>(SubExpr) || + clang::isa<clang::BlockExpr>(SubExpr)) && + "Unexpected SubExpr for CK_UserDefinedConversion."); + if (clang::isa<clang::CXXMemberCallExpr>(SubExpr)) + SubExpr = clang::cast<clang::CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument(); + } + + // If the subexpression we're left with is an implicit cast, look + // through that, too. + } while ((E = clang::dyn_cast<clang::ImplicitCastExpr>(SubExpr))); + + return SubExpr; +} +inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) { + return getSubExprAsWritten(const_cast<clang::CastExpr *>(This)); +} + } #endif |