Extend loplugin:cstylecast to certain function-style casts

...that are equivalent to const_cast or reinterpret_cast, and should arguably
better be written that way for clarity.  Drawing inspiration from
<https://reviews.llvm.org/D76572> "Replace `T(x)` with `reinterpret_cast<T>(x)`
everywhere it means reinterpret_cast. No functional change".

Change-Id: I27b8f70d324d32ecba658db4d1c2db03e10d5d3e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91086
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
This commit is contained in:
Stephan Bergmann 2020-03-26 08:34:37 +01:00
parent 9936f3ed49
commit 1ebeacb20a
14 changed files with 95 additions and 45 deletions

View file

@ -336,7 +336,7 @@ sal_Int32 VtableFactory::createVtables(
code = addLocalFunctions(
&slots, code,
#ifdef USE_DOUBLE_MMAP
sal_uIntPtr(block.exec) - sal_uIntPtr(block.start),
reinterpret_cast<sal_uIntPtr>(block.exec) - reinterpret_cast<sal_uIntPtr>(block.start),
#endif
type2,
baseOffset.getFunctionOffset(type2->aBase.pTypeName),

View file

@ -17,7 +17,9 @@
#include "plugin.hxx"
//
// We don't like using C-style casts in C++ code
// We don't like using C-style casts in C++ code. Similarly, warn about function-style casts (which
// are semantically equivalent to C-style casts) that are not semantically equivalent to static_cast
// and should rather be written as const_cast or reinterpret_cast.
//
namespace {
@ -187,6 +189,8 @@ public:
bool VisitCStyleCastExpr(const CStyleCastExpr * expr);
bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * expr);
private:
bool isConstCast(QualType from, QualType to);
@ -199,6 +203,8 @@ private:
bool rewriteArithmeticCast(CStyleCastExpr const * expr, char const ** replacement);
void reportCast(ExplicitCastExpr const * expr, char const * performsHint);
unsigned int externCContexts_ = 0;
std::set<SourceLocation> rewritten_;
// needed when rewriting in macros, in general to avoid "double code replacement, possible
@ -258,32 +264,35 @@ bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
perf = "const_cast";
}
}
std::string incompFrom;
std::string incompTo;
if( expr->getCastKind() == CK_BitCast ) {
if (resolvePointers(expr->getSubExprAsWritten()->getType())
->isIncompleteType())
reportCast(expr, perf);
return true;
}
bool CStyleCast::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const * expr) {
if (ignoreLocation(expr)) {
return true;
}
char const * perf = nullptr;
switch (expr->getCastKind()) {
case CK_ConstructorConversion:
case CK_Dependent: //TODO: really filter out all of these?
case CK_IntegralCast:
case CK_IntegralToBoolean:
case CK_ToVoid:
return true;
case CK_NoOp:
if (isConstCast(
expr->getSubExprAsWritten()->getType(),
expr->getTypeAsWritten()))
{
incompFrom = "incomplete ";
}
if (resolvePointers(expr->getType())->isIncompleteType()) {
incompTo = "incomplete ";
perf = "const_cast";
break;
}
return true; //TODO: really filter out all of these?
default:
break;
}
if (perf == nullptr) {
perf = recommendedFix(expr->getCastKind());
}
std::string performs;
if (perf != nullptr) {
performs = std::string(" (performs: ") + perf + ")";
}
report(
DiagnosticsEngine::Warning, "C-style cast from %0%1 to %2%3%4 (%5)",
expr->getSourceRange().getBegin())
<< incompFrom << expr->getSubExprAsWritten()->getType()
<< incompTo << expr->getTypeAsWritten() << performs
<< expr->getCastKindName()
<< expr->getSourceRange();
reportCast(expr, perf);
return true;
}
@ -661,6 +670,36 @@ bool CStyleCast::rewriteArithmeticCast(CStyleCastExpr const * expr, char const *
return true;
}
void CStyleCast::reportCast(ExplicitCastExpr const * expr, char const * performsHint) {
std::string incompFrom;
std::string incompTo;
if( expr->getCastKind() == CK_BitCast ) {
if (resolvePointers(expr->getSubExprAsWritten()->getType())
->isIncompleteType())
{
incompFrom = "incomplete ";
}
if (resolvePointers(expr->getType())->isIncompleteType()) {
incompTo = "incomplete ";
}
}
if (performsHint == nullptr) {
performsHint = recommendedFix(expr->getCastKind());
}
std::string performs;
if (performsHint != nullptr) {
performs = std::string(" (performs: ") + performsHint + ")";
}
report(
DiagnosticsEngine::Warning, "%select{C|Function}0-style cast from %1%2 to %3%4%5 (%6)",
expr->getSourceRange().getBegin())
<< isa<CXXFunctionalCastExpr>(expr)
<< incompFrom << expr->getSubExprAsWritten()->getType()
<< incompTo << expr->getTypeAsWritten() << performs
<< expr->getCastKindName()
<< expr->getSourceRange();
}
loplugin::Plugin::Registration< CStyleCast > X("cstylecast", true);
}

View file

@ -7,6 +7,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sal/config.h>
#include <sal/types.h>
namespace N
{
enum E
@ -17,6 +21,13 @@ enum E
using T = unsigned int;
}
void FunctionalCast(void* p)
{
// expected-error@+1 {{Function-style cast from 'void *' to 'sal_IntPtr' (aka 'long') (performs: reinterpret_cast) (PointerToIntegral) [loplugin:cstylecast]}}
auto n = sal_IntPtr(p);
(void(n)); // no warning expected (outer parens to disambiguate expr vs. decl)
}
static const int C
= (int)0; // expected-error {{C-style cast from 'int' to 'int' (performs: functional cast) (NoOp) [loplugin:cstylecast]}}

View file

@ -148,7 +148,7 @@ public:
struct Hash
{
sal_IntPtr operator () ( const PyRef &r) const { return sal_IntPtr( r.get() ); }
sal_IntPtr operator () ( const PyRef &r) const { return reinterpret_cast<sal_IntPtr>( r.get() ); }
};
};

View file

@ -921,7 +921,7 @@ void XclObjOle::WriteSubRecs( XclExpStream& rStrm )
OUString aStorageName( "MBD" );
char aBuf[ sizeof(sal_uInt32) * 2 + 1 ];
// FIXME Eeek! Is this just a way to get a unique id?
sal_uInt32 nPictureId = sal_uInt32(sal_uIntPtr(this) >> 2);
sal_uInt32 nPictureId = sal_uInt32(reinterpret_cast<sal_uIntPtr>(this) >> 2);
sprintf( aBuf, "%08X", static_cast< unsigned int >( nPictureId ) );
aStorageName += OUString::createFromAscii(aBuf);
tools::SvRef<SotStorage> xOleStg = pRootStorage->OpenSotStorage( aStorageName );

View file

@ -71,7 +71,7 @@ namespace pdfi
return sum ^ size_t(rEntry.first.hashCode()) ^ size_t(rEntry.second.hashCode());
});
nRet ^= size_t(Contents.hashCode());
nRet ^= size_t(ContainedElement);
nRet ^= reinterpret_cast<size_t>(ContainedElement);
for( size_t n = 0; n < SubStyles.size(); ++n )
nRet ^= size_t(SubStyles[n]);
return nRet;

View file

@ -941,7 +941,7 @@ Reference<ui::XUIElement> SidebarController::CreateUIElement (
aCreationArguments.put("ParentWindow", makeAny(rxWindow));
SfxDockingWindow* pSfxDockingWindow = dynamic_cast<SfxDockingWindow*>(mpParentWindow.get());
if (pSfxDockingWindow != nullptr)
aCreationArguments.put("SfxBindings", makeAny(sal_uInt64(&pSfxDockingWindow->GetBindings())));
aCreationArguments.put("SfxBindings", makeAny(reinterpret_cast<sal_uInt64>(&pSfxDockingWindow->GetBindings())));
aCreationArguments.put("Theme", Theme::GetPropertySet());
aCreationArguments.put("Sidebar", makeAny(Reference<ui::XSidebar>(static_cast<ui::XSidebar*>(this))));
if (bWantsCanvas)

View file

@ -899,7 +899,7 @@ static auto verifyNestedFieldmark(OUString const& rTestName,
+ u"baz" + OUStringChar(CH_TXT_ATR_FIELDEND)), outerString);
// must return innermost mark
CPPUNIT_ASSERT_EQUAL(sal_uIntPtr(pInner), sal_uIntPtr(rIDMA.getFieldmarkFor(innerPos)));
CPPUNIT_ASSERT_EQUAL(reinterpret_cast<sal_uIntPtr>(pInner), reinterpret_cast<sal_uIntPtr>(rIDMA.getFieldmarkFor(innerPos)));
}
void Test::testNestedFieldmark()

View file

@ -282,10 +282,10 @@ const SwTOXMark& SwDoc::GotoTOXMark( const SwTOXMark& rCurTOXMark,
case TOX_PRV:
if ( (aAbsNew < aAbsIdx && aAbsNew > aPrevPos) ||
(aAbsIdx == aAbsNew &&
(sal_uLong(&rCurTOXMark) > sal_uLong(pTOXMark) &&
(!pNew || aPrevPos < aAbsIdx || sal_uLong(pNew) < sal_uLong(pTOXMark) ) )) ||
(reinterpret_cast<sal_uLong>(&rCurTOXMark) > reinterpret_cast<sal_uLong>(pTOXMark) &&
(!pNew || aPrevPos < aAbsIdx || reinterpret_cast<sal_uLong>(pNew) < reinterpret_cast<sal_uLong>(pTOXMark) ) )) ||
(aPrevPos == aAbsNew && aAbsIdx != aAbsNew &&
sal_uLong(pTOXMark) > sal_uLong(pNew)) )
reinterpret_cast<sal_uLong>(pTOXMark) > reinterpret_cast<sal_uLong>(pNew)) )
{
pNew = pTOXMark;
aPrevPos = aAbsNew;
@ -304,10 +304,10 @@ const SwTOXMark& SwDoc::GotoTOXMark( const SwTOXMark& rCurTOXMark,
case TOX_NXT:
if ( (aAbsNew > aAbsIdx && aAbsNew < aNextPos) ||
(aAbsIdx == aAbsNew &&
(sal_uLong(&rCurTOXMark) < sal_uLong(pTOXMark) &&
(!pNew || aNextPos > aAbsIdx || sal_uLong(pNew) > sal_uLong(pTOXMark)) )) ||
(reinterpret_cast<sal_uLong>(&rCurTOXMark) < reinterpret_cast<sal_uLong>(pTOXMark) &&
(!pNew || aNextPos > aAbsIdx || reinterpret_cast<sal_uLong>(pNew) > reinterpret_cast<sal_uLong>(pTOXMark)) )) ||
(aNextPos == aAbsNew && aAbsIdx != aAbsNew &&
sal_uLong(pTOXMark) < sal_uLong(pNew)) )
reinterpret_cast<sal_uLong>(pTOXMark) < reinterpret_cast<sal_uLong>(pNew)) )
{
pNew = pTOXMark;
aNextPos = aAbsNew;

View file

@ -1285,7 +1285,7 @@ void SwNoTextFrame::PaintPicture( vcl::RenderContext* pOut, const SwRect &rGrfAr
"pOut should not be a virtual device" );
pGrfNd->StartGraphicAnimation(pOut, aAlignedGrfArea.Pos(),
aAlignedGrfArea.SSize(), sal_IntPtr(this),
aAlignedGrfArea.SSize(), reinterpret_cast<sal_IntPtr>(this),
pVout );
}
else
@ -1536,7 +1536,7 @@ void SwNoTextFrame::StopAnimation( OutputDevice* pOut ) const
if( pGrfNd && pGrfNd->IsAnimated() )
{
const_cast< SwGrfNode* >(pGrfNd)->StopGraphicAnimation( pOut, sal_IntPtr(this) );
const_cast< SwGrfNode* >(pGrfNd)->StopGraphicAnimation( pOut, reinterpret_cast<sal_IntPtr>(this) );
}
}

View file

@ -3841,7 +3841,7 @@ bool SwFlyFrame::IsPaint( SdrObject *pObj, const SwViewShell *pSh )
{
if ( !pAnch->isFrameAreaPositionValid() )
pAnch = nullptr;
else if ( sal_IntPtr(pSh->GetOut()) == sal_IntPtr(pSh->getIDocumentDeviceAccess().getPrinter( false )))
else if ( reinterpret_cast<sal_IntPtr>(pSh->GetOut()) == reinterpret_cast<sal_IntPtr>(pSh->getIDocumentDeviceAccess().getPrinter( false )))
{
//HACK: we have to omit some of the objects for printing,
//otherwise they would be printed twice.

View file

@ -932,7 +932,7 @@ void SwGrfNumPortion::Paint( const SwTextPaintInfo &rInf ) const
bDraw = !rInf.GetOpt().IsGraphic();
if( !nId )
{
SetId( sal_IntPtr( rInf.GetTextFrame() ) );
SetId( reinterpret_cast<sal_IntPtr>( rInf.GetTextFrame() ) );
rInf.GetTextFrame()->SetAnimation();
}
if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )

View file

@ -453,7 +453,7 @@ void DeInitVCL()
aBuf.append( "\" type = \"" );
aBuf.append( typeid(*pWin).name() );
aBuf.append( "\", ptr = 0x" );
aBuf.append( sal_Int64( pWin ), 16 );
aBuf.append( reinterpret_cast<sal_Int64>( pWin ), 16 );
aBuf.append( "\n" );
}
}

View file

@ -8262,9 +8262,9 @@ private:
if (bContinue && !sText.isEmpty())
{
OString sFinalText(OUStringToOString(sText, RTL_TEXTENCODING_UTF8));
g_signal_handlers_block_by_func(pEntry, gpointer(signalInsertText), this);
g_signal_handlers_block_by_func(pEntry, reinterpret_cast<gpointer>(signalInsertText), this);
gtk_editable_insert_text(GTK_EDITABLE(pEntry), sFinalText.getStr(), sFinalText.getLength(), position);
g_signal_handlers_unblock_by_func(pEntry, gpointer(signalInsertText), this);
g_signal_handlers_unblock_by_func(pEntry, reinterpret_cast<gpointer>(signalInsertText), this);
}
g_signal_stop_emission_by_name(pEntry, "insert-text");
}
@ -12286,9 +12286,9 @@ private:
if (bContinue && !sText.isEmpty())
{
OString sFinalText(OUStringToOString(sText, RTL_TEXTENCODING_UTF8));
g_signal_handlers_block_by_func(pEntry, gpointer(signalEntryInsertText), this);
g_signal_handlers_block_by_func(pEntry, reinterpret_cast<gpointer>(signalEntryInsertText), this);
gtk_editable_insert_text(GTK_EDITABLE(pEntry), sFinalText.getStr(), sFinalText.getLength(), position);
g_signal_handlers_unblock_by_func(pEntry, gpointer(signalEntryInsertText), this);
g_signal_handlers_unblock_by_func(pEntry, reinterpret_cast<gpointer>(signalEntryInsertText), this);
}
g_signal_stop_emission_by_name(pEntry, "insert-text");
}