Kaydet (Commit) 9d80c032 authored tarafından Stephan Bergmann's avatar Stephan Bergmann

loplugin:redundantcast: redundant static_casts

Change-Id: I4d50b77745d68a23136221ef06f327137e89fa7e
üst 1257344e
......@@ -67,6 +67,15 @@ TypeCheck TypeCheck::Pointer() const {
return TypeCheck();
}
TypeCheck TypeCheck::Typedef() const {
if (!type_.isNull()) {
if (auto const t = type_->getAs<clang::TypedefType>()) {
return TypeCheck(t->desugar());
}
}
return TypeCheck();
}
TypeCheck TypeCheck::NotSubstTemplateTypeParmType() const {
return
(!type_.isNull()
......
......@@ -48,6 +48,11 @@ public:
template<std::size_t N> inline ContextCheck Class(char const (& id)[N])
const;
TypeCheck Typedef() const;
template<std::size_t N> inline ContextCheck Typedef(char const (& id)[N])
const;
TypeCheck NotSubstTemplateTypeParmType() const;
private:
......@@ -152,6 +157,22 @@ template<std::size_t N> ContextCheck TypeCheck::Class(char const (& id)[N])
return ContextCheck();
}
template<std::size_t N> ContextCheck TypeCheck::Typedef(char const (& id)[N])
const
{
if (!type_.isNull()) {
if (auto const t = type_->getAs<clang::TypedefType>()) {
auto const d = t->getDecl();
auto const i = d->getIdentifier();
assert(i != nullptr);
if (i->isStr(id)) {
return ContextCheck(d->getDeclContext());
}
}
}
return ContextCheck();
}
template<std::size_t N> ContextCheck DeclCheck::Class(char const (& id)[N])
const
{
......
......@@ -25,10 +25,83 @@
#include "clang/Sema/Sema.h"
#include "check.hxx"
#include "plugin.hxx"
namespace {
// 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 {
Expr *skipImplicitTemporary(Expr *expr) {
// Skip through reference binding to temporary.
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(expr))
expr = Materialize->GetTemporaryExpr();
// Skip any temporary bindings; they're implicit.
if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(expr))
expr = Binder->getSubExpr();
return expr;
}
}
Expr *getSubExprAsWritten(CastExpr *This) {
Expr *SubExpr = nullptr;
CastExpr *E = This;
do {
SubExpr = skipImplicitTemporary(E->getSubExpr());
// Conversions by constructor and conversion functions have a
// subexpression describing the call; strip it off.
if (E->getCastKind() == CK_ConstructorConversion)
SubExpr =
skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr)->getArg(0));
else if (E->getCastKind() == CK_UserDefinedConversion) {
assert((isa<CXXMemberCallExpr>(SubExpr) ||
isa<BlockExpr>(SubExpr)) &&
"Unexpected SubExpr for CK_UserDefinedConversion.");
if (isa<CXXMemberCallExpr>(SubExpr))
SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
}
// If the subexpression we're left with is an implicit cast, look
// through that, too.
} while ((E = dyn_cast<ImplicitCastExpr>(SubExpr)));
return SubExpr;
}
const Expr *getSubExprAsWritten(const CastExpr *This) {
return getSubExprAsWritten(const_cast<CastExpr *>(This));
}
bool isVoidPointer(QualType type) {
return type->isPointerType()
&& type->getAs<clang::PointerType>()->getPointeeType()->isVoidType();
......@@ -49,6 +122,8 @@ public:
bool VisitImplicitCastExpr(ImplicitCastExpr const * expr);
bool VisitCXXStaticCastExpr(CXXStaticCastExpr const * expr);
bool VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr const * expr);
bool VisitCXXConstCastExpr(CXXConstCastExpr const * expr);
......@@ -205,6 +280,48 @@ bool RedundantCast::VisitImplicitCastExpr(const ImplicitCastExpr * expr) {
return true;
}
bool RedundantCast::VisitCXXStaticCastExpr(CXXStaticCastExpr const * expr) {
if (ignoreLocation(expr)) {
return true;
}
auto t1 = getSubExprAsWritten(expr)->getType();
auto t2 = expr->getTypeAsWritten();
if (t1.getCanonicalType() != t2.getCanonicalType()
|| t1->isArithmeticType())
{
return true;
}
// Don't warn about
//
// *pResult = static_cast<oslModule>(RTLD_DEFAULT);
//
// in osl_getModuleHandle (sal/osl/unx/module.cxx) (where oslModule is a
// typedef to void *):
if (loplugin::TypeCheck(t2).Typedef("oslModule").GlobalNamespace()
&& !loplugin::TypeCheck(t1).Typedef())
{
return true;
}
// Dont't warn about
//
// curl_easy_setopt(static_cast<CURL*>(pData),
// CURLOPT_HEADERFUNCTION,
// memory_write_dummy);
//
// in delete_CURL (ucb/source/ucp/ftp/ftploaderthread.cxx) (where CURL is a
// typedef to void):
if (loplugin::TypeCheck(t2).Pointer().Typedef("CURL").GlobalNamespace()
&& !loplugin::TypeCheck(t1).Pointer().Typedef())
{
return true;
}
report(
DiagnosticsEngine::Warning,
"redundant static_cast from %0 to %1", expr->getExprLoc())
<< t1 << t2 << expr->getSourceRange();
return true;
}
bool RedundantCast::VisitCXXReinterpretCastExpr(
CXXReinterpretCastExpr const * expr)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment