summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/compat.hxx
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2017-05-19 23:51:46 +0200
committerStephan Bergmann <sbergman@redhat.com>2017-05-19 23:57:03 +0200
commit8b1fcedcd10366523967ebcbd463b2c0c6b5b17a (patch)
tree094af692230758812f3deb2828b0d1a5e22e4cb0 /compilerplugins/clang/compat.hxx
parenta9a5fc3708406561399153d0bf44d8c323c9263e (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.hxx73
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