loplugin:cstylecast: deal with those that are (technically) const_cast

Change-Id: Ice7bbdea1d0df0a92f2e1b38f033adaff2fb8b07
This commit is contained in:
Stephan Bergmann
2015-06-02 11:29:13 +02:00
parent 3f846cb7a4
commit acd4ecc38f

View File

@@ -18,6 +18,63 @@
namespace { namespace {
bool areSimilar(QualType type1, QualType type2) {
auto t1 = type1.getCanonicalType().getTypePtr();
auto t2 = type2.getCanonicalType().getTypePtr();
for (;;) {
if (t1->isPointerType()) {
if (!t2->isPointerType()) {
return false;
}
auto t1a = t1->getAs<PointerType>();
auto t2a = t2->getAs<PointerType>();
t1 = t1a->getPointeeType().getTypePtr();
t2 = t2a->getPointeeType().getTypePtr();
} else if (t1->isMemberPointerType()) {
if (!t2->isMemberPointerType()) {
return false;
}
auto t1a = t1->getAs<MemberPointerType>();
auto t2a = t2->getAs<MemberPointerType>();
if (t1a->getClass()->getCanonicalTypeInternal()
!= t2a->getClass()->getCanonicalTypeInternal())
{
return false;
}
t1 = t1a->getPointeeType().getTypePtr();
t2 = t2a->getPointeeType().getTypePtr();
} else if (t1->isConstantArrayType()) {
if (!t2->isConstantArrayType()) {
return false;
}
auto t1a = static_cast<ConstantArrayType const *>(
t1->getAsArrayTypeUnsafe());
auto t2a = static_cast<ConstantArrayType const *>(
t2->getAsArrayTypeUnsafe());
if (t1a->getSize() != t2a->getSize()) {
return false;
}
t1 = t1a->getElementType().getTypePtr();
t2 = t2a->getElementType().getTypePtr();
} else if (t1->isIncompleteArrayType()) {
if (!t2->isIncompleteArrayType()) {
return false;
}
auto t1a = static_cast<IncompleteArrayType const *>(
t1->getAsArrayTypeUnsafe());
auto t2a = static_cast<IncompleteArrayType const *>(
t2->getAsArrayTypeUnsafe());
t1 = t1a->getElementType().getTypePtr();
t2 = t2a->getElementType().getTypePtr();
} else {
return false;
}
if (t1 == t2) {
return true;
}
}
}
bool hasCLanguageLinkageType(FunctionDecl const * decl) { bool hasCLanguageLinkageType(FunctionDecl const * decl) {
return decl->isExternC() || compat::isInExternCContext(*decl); return decl->isExternC() || compat::isInExternCContext(*decl);
} }
@@ -48,6 +105,8 @@ public:
bool VisitCStyleCastExpr(const CStyleCastExpr * expr); bool VisitCStyleCastExpr(const CStyleCastExpr * expr);
private: private:
bool isConstCast(QualType from, QualType to);
bool externCFunction; bool externCFunction;
}; };
@@ -56,7 +115,7 @@ static const char * recommendedFix(clang::CastKind ck) {
case CK_IntegralToPointer: return "reinterpret_cast"; case CK_IntegralToPointer: return "reinterpret_cast";
case CK_PointerToIntegral: return "reinterpret_cast"; case CK_PointerToIntegral: return "reinterpret_cast";
case CK_BaseToDerived: return "static_cast"; case CK_BaseToDerived: return "static_cast";
default: return "???"; default: return nullptr;
} }
} }
@@ -88,6 +147,7 @@ bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
if( expr->getCastKind() == CK_IntegralCast ) { if( expr->getCastKind() == CK_IntegralCast ) {
return true; return true;
} }
char const * perf = nullptr;
if( expr->getCastKind() == CK_NoOp ) { if( expr->getCastKind() == CK_NoOp ) {
QualType t1 = expr->getSubExpr()->getType(); QualType t1 = expr->getSubExpr()->getType();
QualType t2 = expr->getType(); QualType t2 = expr->getType();
@@ -100,11 +160,17 @@ bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
} else { } else {
return true; return true;
} }
if (expr->getSubExprAsWritten()->getType() != expr->getType() if (isConstCast(
&& (!t1.isMoreQualifiedThan(t2) expr->getSubExprAsWritten()->getType(),
|| (t1.getUnqualifiedType().getCanonicalType().getTypePtr() expr->getTypeAsWritten()))
!= (t2.getUnqualifiedType().getCanonicalType() {
.getTypePtr())))) perf = "const_cast";
} else if (expr->getSubExprAsWritten()->getType() != expr->getType()
&& (!t1.isMoreQualifiedThan(t2)
|| ((t1.getUnqualifiedType().getCanonicalType()
.getTypePtr())
!= (t2.getUnqualifiedType().getCanonicalType()
.getTypePtr()))))
{ {
return true; return true;
} }
@@ -130,18 +196,43 @@ bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
return true; return true;
} }
} }
if (perf == nullptr) {
perf = recommendedFix(expr->getCastKind());
}
std::string performs;
if (perf != nullptr) {
performs = std::string(" (performs: ") + perf + ")";
}
report( report(
DiagnosticsEngine::Warning, DiagnosticsEngine::Warning, "%0 C-style cast from %1%2 to %3%4%5",
"c-style cast, type=%0, from=%1%2, to=%3%4, recommendedFix=%5",
expr->getSourceRange().getBegin()) expr->getSourceRange().getBegin())
<< expr->getCastKind() << expr->getCastKindName() << incompFrom
<< incompFrom << expr->getSubExprAsWritten()->getType() << expr->getSubExprAsWritten()->getType() << incompTo << expr->getType()
<< incompTo << expr->getType() << performs << expr->getSourceRange();
<< recommendedFix(expr->getCastKind())
<< expr->getSourceRange();
return true; return true;
} }
bool CStyleCast::isConstCast(QualType from, QualType to) {
if (to->isReferenceType()
&& to->getAs<ReferenceType>()->getPointeeType()->isObjectType())
{
if (!from->isObjectType()) {
return false;
}
from = compiler.getASTContext().getPointerType(from);
to = compiler.getASTContext().getPointerType(
to->getAs<ReferenceType>()->getPointeeType());
} else {
if (from->isArrayType()) {
from = compiler.getASTContext().getPointerType(
from->getAsArrayTypeUnsafe()->getElementType());
} else if (from->isFunctionType()) {
compiler.getASTContext().getPointerType(from);
}
}
return areSimilar(from, to);
}
loplugin::Plugin::Registration< CStyleCast > X("cstylecast"); loplugin::Plugin::Registration< CStyleCast > X("cstylecast");
} }