loplugin:cstylecast: deal with those that are (technically) const_cast
Change-Id: Ice7bbdea1d0df0a92f2e1b38f033adaff2fb8b07
This commit is contained in:
@@ -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");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user