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"
2015-11-17 21:50:45 +01:00
# include "typecheck.hxx"
2015-10-30 16:05:42 +01:00
namespace {
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-17 15:05:34 +01:00
static std : : pair < bool , std : : vector < FieldDecl const * > > isBadStaticType (
QualType const & rpType , std : : vector < FieldDecl const * > & chain ,
2015-11-12 22:33:36 +01:00
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 ) ;
2015-11-17 15:05:34 +01:00
return isBadStaticType ( pPointee , chain , copy ) ;
2015-11-12 22:33:36 +01:00
} else {
2015-11-17 15:05:34 +01:00
return std : : make_pair ( false , std : : vector < FieldDecl const * > ( ) ) ;
2015-11-12 22:33:36 +01:00
}
}
2015-11-05 13:16:50 +01:00
RecordType const * const pRecordType ( pCanonical - > getAs < RecordType > ( ) ) ;
if ( ! pRecordType ) {
2015-11-17 15:05:34 +01:00
return std : : make_pair ( false , std : : vector < FieldDecl const * > ( ) ) ;
2015-11-05 13:16:50 +01:00
}
2015-12-08 22:56:02 +01:00
auto const type = loplugin : : TypeCheck ( rpType ) ;
if ( type . Class ( " Image " ) . GlobalNamespace ( )
| | type . Class ( " Bitmap " ) . GlobalNamespace ( )
| | type . Class ( " BitmapEx " ) . GlobalNamespace ( )
2016-04-14 15:07:57 +02:00
| | type . Class ( " VclPtr " ) . GlobalNamespace ( )
2015-11-05 13:16:50 +01:00
)
{
2015-11-17 15:05:34 +01:00
return std : : make_pair ( true , chain ) ;
2015-11-05 13:16:50 +01:00
}
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
2015-11-17 15:05:34 +01:00
return std : : make_pair ( false , std : : vector < FieldDecl const * > ( ) ) ;
2015-11-12 22:33:36 +01:00
}
2015-12-08 22:56:02 +01:00
if ( type . Class ( " DeleteOnDeinit " ) . Namespace ( " vcl " ) . GlobalNamespace ( )
| | type . Class ( " weak_ptr " ) . StdNamespace ( ) // not owning
| | type . Class ( " ImplWallpaper " ) . GlobalNamespace ( ) // very odd static instance here
| | type . Class ( " Application " ) . GlobalNamespace ( ) // numerous odd subclasses in vclmain::createApplication()
| | type . Class ( " DemoMtfApp " ) . GlobalNamespace ( ) // one of these Application with own VclPtr
2015-11-12 22:33:36 +01:00
)
{
2015-11-17 15:05:34 +01:00
return std : : make_pair ( false , std : : vector < FieldDecl const * > ( ) ) ;
2015-11-12 22:33:36 +01:00
}
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-17 15:05:34 +01:00
chain . push_back ( * it ) ;
auto const ret ( isBadStaticType ( ( * it ) - > getType ( ) , chain , copy ) ) ;
chain . pop_back ( ) ;
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-17 15:05:34 +01:00
auto const ret ( isBadStaticType ( ( * it ) . getType ( ) , chain , 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-17 15:05:34 +01:00
auto const ret ( isBadStaticType ( ( * it ) . getType ( ) , chain , copy ) ) ;
2015-11-05 13:16:50 +01:00
if ( ret . first ) {
return ret ;
}
}
2015-11-17 15:05:34 +01:00
return std : : make_pair ( false , std : : vector < FieldDecl const * > ( ) ) ;
2015-11-05 13:16:50 +01:00
}
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 = = " 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
2015-11-26 10:17:41 +01:00
| | name = = " s_pVout " // _FrameFinit()
2015-11-12 22:33:36 +01:00
| | name = = " s_pPaintQueue " // SwPaintQueue::Remove()
| | name = = " gProp " // only owned (VclPtr) member cleared again
2015-11-26 09:58:15 +01:00
| | name = = " g_pColumnCacheLastTabFrame " // not owning
| | name = = " g_pColumnCacheLastCellFrame " // not owning
| | name = = " g_pRowCacheLastTabFrame " // not owning
| | name = = " g_pRowCacheLastCellFrame " // not owning
2015-11-12 22:33:36 +01:00
| | 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()
2015-11-17 23:43:26 +01:00
| | name = = " s_ImplImageTree "
2015-11-17 16:28:33 +01:00
// ImplImageTree::get(), ImplImageTree::shutDown()
2015-11-17 16:41:40 +01:00
| | name = = " s_pMouseFrame "
// vcl/osx/salframeview.mm, mouseEntered/Exited, not owning
| | name = = " pCurrentMenuBar "
// vcl/osx/salmenu.cxx, AquaSalMenu::set/unsetMainMenu, not
// owning
| | name = = " s_pCaptureFrame " // vcl/osx/salframe.cxx, not owning
2015-11-17 19:38:41 +01:00
| | name = = " pBlink "
// sw/source/core/text/blink.cxx, _TextFinit()
2015-11-17 23:43:26 +01:00
| | name = = " s_pIconCache "
2015-11-17 21:31:46 +01:00
// sd/source/ui/tools/IconCache.cxx, leaked
2015-11-12 22:33:36 +01:00
) // these variables appear unproblematic
{
return true ;
}
2016-04-18 11:21:44 +02:00
// these two are fairly harmless because they're both empty objects
if ( name = = " s_xEmptyController " // svx/source/fmcomp/gridcell.cxx
2016-04-14 15:07:57 +02:00
| | name = = " xCell " // svx/source/table/svdotable.cxx
)
{
return true ;
}
// ignore pointers, nothing happens to them on shutdown
QualType const pCanonical ( pVarDecl - > getType ( ) . getUnqualifiedType ( ) . getCanonicalType ( ) ) ;
if ( pCanonical - > isPointerType ( ) ) {
return true ;
}
2015-11-17 15:05:34 +01:00
std : : vector < FieldDecl const * > pad ;
auto const ret ( isBadStaticType ( pVarDecl - > getType ( ) , pad ,
2015-11-12 22:33:36 +01:00
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-17 15:05:34 +01:00
for ( auto i : ret . second ) {
2015-11-17 14:27:05 +01:00
report ( DiagnosticsEngine : : Note ,
2015-11-17 15:05:34 +01:00
" ... due to this member of %0 " ,
i - > getLocation ( ) )
< < i - > getParent ( ) < < i - > getSourceRange ( ) ;
2015-11-05 13:16:50 +01:00
}
2015-10-30 16:05:42 +01:00
}
}
return true ;
}
} ;
loplugin : : Plugin : : Registration < BadStatics > X ( " badstatics " ) ;
} // namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */