2015-10-30 16:05:42 +01:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*/
# include "plugin.hxx"
namespace {
2015-11-12 22:33:36 +01:00
static bool startsWith ( const std : : string & s , const char * other )
{
return s . compare ( 0 , strlen ( other ) , other ) = = 0 ;
}
2015-10-30 16:05:42 +01:00
class BadStatics
: public clang : : RecursiveASTVisitor < BadStatics >
, public loplugin : : Plugin
{
public :
explicit BadStatics ( InstantiationData const & rData ) : Plugin ( rData ) { }
void run ( ) override {
if ( compiler . getLangOpts ( ) . CPlusPlus ) { // no non-trivial dtors in C
TraverseDecl ( compiler . getASTContext ( ) . getTranslationUnitDecl ( ) ) ;
}
}
2015-11-12 22:33:36 +01:00
static std : : pair < bool , FieldDecl const * > isBadStaticType (
QualType const & rpType , FieldDecl const * const pCurrentFieldDecl ,
std : : vector < QualType > const & rParents )
2015-11-05 13:16:50 +01:00
{
2015-11-12 22:33:36 +01:00
QualType const pCanonical ( rpType . getUnqualifiedType ( ) . getCanonicalType ( ) ) ;
if ( pCanonical - > isPointerType ( ) | | pCanonical - > isReferenceType ( ) ) {
QualType const pPointee ( pCanonical - > getPointeeType ( ) . getUnqualifiedType ( ) . getCanonicalType ( ) ) ;
auto const iter ( std : : find ( rParents . begin ( ) , rParents . end ( ) , pPointee ) ) ;
if ( iter = = rParents . end ( ) )
{
std : : vector < QualType > copy ( rParents ) ;
copy . push_back ( pCanonical ) ;
return isBadStaticType ( pPointee , pCurrentFieldDecl , copy ) ;
} else {
return std : : make_pair ( false , nullptr ) ;
}
}
2015-11-05 13:16:50 +01:00
RecordType const * const pRecordType ( pCanonical - > getAs < RecordType > ( ) ) ;
if ( ! pRecordType ) {
return std : : make_pair ( false , nullptr ) ;
}
auto const type ( pCanonical . getAsString ( ) ) ;
if ( type = = " class Image "
| | type = = " class Bitmap "
| | type = = " class BitmapEx "
)
{
return std : : make_pair ( true , pCurrentFieldDecl ) ;
}
RecordDecl const * const pDefinition ( pRecordType - > getDecl ( ) - > getDefinition ( ) ) ;
2015-11-12 22:33:36 +01:00
if ( ! pDefinition ) { // maybe no definition if it's a pointer/reference
return std : : make_pair ( false , nullptr ) ;
}
if ( startsWith ( type , " class vcl::DeleteOnDeinit " )
| | startsWith ( type , " class std::weak_ptr " ) // not owning
| | type = = " class ImplWallpaper " // very odd static instance here
| | type = = " class Application " // numerous odd subclasses in vclmain::createApplication()
| | type = = " class DemoMtfApp " // one of these Application with own VclPtr
)
{
return std : : make_pair ( false , nullptr ) ;
}
std : : vector < QualType > copy ( rParents ) ;
copy . push_back ( pCanonical ) ;
2015-11-05 13:16:50 +01:00
CXXRecordDecl const * const pDecl ( dyn_cast < CXXRecordDecl > ( pDefinition ) ) ;
assert ( pDecl ) ;
for ( auto it = pDecl - > field_begin ( ) ; it ! = pDecl - > field_end ( ) ; + + it ) {
2015-11-12 22:33:36 +01:00
auto const ret ( isBadStaticType ( ( * it ) - > getType ( ) , * it , copy ) ) ;
2015-11-05 13:16:50 +01:00
if ( ret . first ) {
return ret ;
}
}
for ( auto it = pDecl - > bases_begin ( ) ; it ! = pDecl - > bases_end ( ) ; + + it ) {
2015-11-12 22:33:36 +01:00
auto const ret ( isBadStaticType ( ( * it ) . getType ( ) , pCurrentFieldDecl , copy ) ) ;
2015-11-05 13:16:50 +01:00
if ( ret . first ) {
return ret ;
}
}
for ( auto it = pDecl - > vbases_begin ( ) ; it ! = pDecl - > vbases_end ( ) ; + + it ) {
2015-11-12 22:33:36 +01:00
auto const ret ( isBadStaticType ( ( * it ) . getType ( ) , pCurrentFieldDecl , copy ) ) ;
2015-11-05 13:16:50 +01:00
if ( ret . first ) {
return ret ;
}
}
return std : : make_pair ( false , nullptr ) ;
}
2015-10-30 16:05:42 +01:00
bool VisitVarDecl ( VarDecl const * const pVarDecl )
{
if ( ignoreLocation ( pVarDecl ) ) {
return true ;
}
2015-11-05 13:16:50 +01:00
if ( pVarDecl - > hasGlobalStorage ( )
& & pVarDecl - > isThisDeclarationADefinition ( ) )
{
2015-11-12 22:33:36 +01:00
auto const name ( pVarDecl - > getName ( ) ) ;
if ( name = = " g_pI18NStatusInstance " // I18NStatus::free()
| | name = = " s_pPreviousView " // not a owning pointer
| | name = = " s_pDefCollapsed " // SvImpLBox::~SvImpLBox()
| | name = = " s_pDefExpanded " // SvImpLBox::~SvImpLBox()
| | name = = " g_pDDSource " // SvTreeListBox::dispose()
| | name = = " g_pDDTarget " // SvTreeListBox::dispose()
| | name = = " g_pSfxApplication " // SfxApplication::~SfxApplication()
| | name = = " s_SidebarResourceManagerInstance " // ResourceManager::disposeDecks()
| | name = = " pStaticThesSubMenu " // wtf is this nonsense
| | name = = " s_pGallery " // this is not entirely clear but apparently the GalleryThemeCacheEntry are deleted by GalleryBrowser2::SelectTheme() or GalleryBrowser2::dispose()
| | name = = " s_ExtMgr " // TheExtensionManager::disposing()
| | name = = " s_pDocLockedInsertingLinks " // not owning
| | name = = " s_pVout " // _FrmFinit()
| | name = = " s_pPaintQueue " // SwPaintQueue::Remove()
| | name = = " gProp " // only owned (VclPtr) member cleared again
| | name = = " g_pColumnCacheLastTabFrm " // not owning
| | name = = " g_pColumnCacheLastCellFrm " // not owning
| | name = = " g_pRowCacheLastTabFrm " // not owning
| | name = = " g_pRowCacheLastCellFrm " // not owning
| | name = = " g_OszCtrl " // SwCrsrOszControl::Exit()
| | name = = " g_pSpellIter " // SwEditShell::SpellEnd()
| | name = = " g_pConvIter " // SwEditShell::SpellEnd()
| | name = = " g_pHyphIter " // SwEditShell::HyphEnd()
| | name = = " pFieldEditEngine " // ScGlobal::Clear()
| | name = = " xDrawClipDocShellRef " // ScGlobal::Clear()
) // these variables appear unproblematic
{
return true ;
}
auto const ret ( isBadStaticType ( pVarDecl - > getType ( ) , nullptr ,
std : : vector < QualType > ( ) ) ) ;
2015-11-05 13:16:50 +01:00
if ( ret . first ) {
2015-10-30 16:05:42 +01:00
report ( DiagnosticsEngine : : Warning ,
" bad static variable causes crash on shutdown " ,
pVarDecl - > getLocation ( ) )
< < pVarDecl - > getSourceRange ( ) ;
2015-11-05 13:16:50 +01:00
if ( ret . second ! = nullptr ) {
2015-11-17 14:27:05 +01:00
report ( DiagnosticsEngine : : Note ,
2015-11-05 13:16:50 +01:00
" ... due to this member " ,
ret . second - > getLocation ( ) )
< < ret . second - > getSourceRange ( ) ;
}
2015-10-30 16:05:42 +01:00
}
}
return true ;
}
} ;
loplugin : : Plugin : : Registration < BadStatics > X ( " badstatics " ) ;
} // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */