loplugin:unusedmethods ucb

Change-Id: Idc0ca78da8ebbdfe8489eee92a1167eb1bd9722f
Reviewed-on: https://gerrit.libreoffice.org/16794
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
diff --git a/compilerplugins/clang/unusedmethods.cxx b/compilerplugins/clang/unusedmethods.cxx
index e45ee7f..bdd606b9 100644
--- a/compilerplugins/clang/unusedmethods.cxx
+++ b/compilerplugins/clang/unusedmethods.cxx
@@ -10,6 +10,7 @@
#include <cassert>
#include <string>
#include <iostream>
#include <fstream>
#include <set>
#include "plugin.hxx"
#include "compat.hxx"
@@ -18,13 +19,12 @@
Dump a list of calls to methods, and a list of method definitions.
Then we will post-process the 2 lists and find the set of unused methods.

Be warned that it produces around 3G of log file.
Be warned that it produces around 2.4G of log file.

The process goes something like this:
  $ make check
  $ make FORCE_COMPILE_ALL=1 COMPILER_PLUGIN_TOOL='unusedmethods' check > log.txt
  $ grep -P '(call:)|(definition:)' log.txt | sort -u > log2.txt
  $ ./compilerplugins/clang/unusedmethods.py log2.txt > result.txt
  $ make FORCE_COMPILE_ALL=1 COMPILER_PLUGIN_TOOL='unusedmethods' check
  $ ./compilerplugins/clang/unusedmethods.py unusedmethods.log > result.txt

and then
  $ for dir in *; do make FORCE_COMPILE_ALL=1 UPDATE_FILES=$dir COMPILER_PLUGIN_TOOL='unusedmethodsremove' $dir; done
@@ -44,13 +44,33 @@ TODO track instantiations of template class constructor methods

namespace {

// try to limit the volumninous output a little
static std::set<std::string> callSet;
static std::set<std::string> definitionSet;


class UnusedMethods:
    public RecursiveASTVisitor<UnusedMethods>, public loplugin::Plugin
{
public:
    explicit UnusedMethods(InstantiationData const & data): Plugin(data) {}

    virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
    virtual void run() override
    {
        TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());

        // dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
        // writing to the same logfile
        std::string output;
        for (const std::string & s : callSet)
            output += "call:\t" + s + "\t\n";
        for (const std::string & s : definitionSet)
            output += "definition:\t" + s + "\t\n";
        ofstream myfile;
        myfile.open("/home/noel/libo4/unusedmethods.log", ios::app | ios::out);
        myfile << output;
        myfile.close();
    }

    bool VisitCallExpr(CallExpr* );
    bool VisitCXXMethodDecl( const CXXMethodDecl* decl );
@@ -80,13 +100,11 @@ static std::string niceName(const CXXMethodDecl* functionDecl)
    return s;
}

// try to limit the volumninous output a little
static std::set<std::string> alreadySeenCallSet;

static void logCallToRootMethods(const CXXMethodDecl* decl)
{
    // For virtual/overriding methods, we need to pretend we called the root method(s),
    // so that they get marked as used.
    decl = decl->getCanonicalDecl();
    bool bPrinted = false;
    for(CXXMethodDecl::method_iterator it = decl->begin_overridden_methods();
        it != decl->end_overridden_methods(); ++it)
@@ -97,8 +115,7 @@ static void logCallToRootMethods(const CXXMethodDecl* decl)
    if (!bPrinted)
    {
        std::string s = niceName(decl);
        if (alreadySeenCallSet.insert(s).second)
            cout << "call:\t" << niceName(decl) << endl;
        callSet.insert(s);
    }
}

@@ -173,7 +190,7 @@ bool UnusedMethods::VisitCXXMethodDecl( const CXXMethodDecl* functionDecl )
        return true;
    }

    cout << "definition:\t" << niceName(functionDecl) << endl;
    definitionSet.insert(niceName(functionDecl));
    return true;
}

diff --git a/compilerplugins/clang/unusedmethods.py b/compilerplugins/clang/unusedmethods.py
index 4b17f95..3ee4b38 100755
--- a/compilerplugins/clang/unusedmethods.py
+++ b/compilerplugins/clang/unusedmethods.py
@@ -33,15 +33,19 @@ exclusionSet = set([
    ])


# The parsing here is designed to also grab output which is mixed into the output from gbuild.
# I have not yet found a way of suppressing the gbuild output.
with open(sys.argv[1]) as txt:
    for line in txt:
        if line.startswith("definition:\t"):
            idx1 = line.find("\t")
            clazzName = line[idx1+1 : len(line)-1]
        if line.find("definition:\t") != -1:
            idx1 = line.find("definition:\t")
            idx2 = line.find("\t", idx1+12)
            clazzName = line[idx1+12 : idx2]
            definitionSet.add(clazzName)
        elif line.startswith("call:\t"):
            idx1 = line.find("\t")
            clazzName = line[idx1+1 : len(line)-1]
        elif line.find("call:\t") != -1:
            idx1 = line.find("call:\t")
            idx2 = line.find("\t", idx1+6)
            clazzName = line[idx1+6 : idx2]
            callSet.add(clazzName)

for clazz in sorted(definitionSet - callSet - exclusionSet):
diff --git a/ucb/source/ucp/cmis/cmis_content.hxx b/ucb/source/ucp/cmis/cmis_content.hxx
index 160ae1e..2fe633b 100644
--- a/ucb/source/ucp/cmis/cmis_content.hxx
+++ b/ucb/source/ucp/cmis/cmis_content.hxx
@@ -109,8 +109,6 @@ private:
    OUString cancelCheckOut( const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment > & xEnv )
            throw( com::sun::star::uno::Exception );

    void destroy( ) throw( com::sun::star::uno::Exception );

    static void copyData( com::sun::star::uno::Reference< com::sun::star::io::XInputStream > xIn,
        com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xOut );

diff --git a/ucb/source/ucp/file/bc.cxx b/ucb/source/ucp/file/bc.cxx
index c1e12b6..f49b152 100644
--- a/ucb/source/ucp/file/bc.cxx
+++ b/ucb/source/ucp/file/bc.cxx
@@ -1364,9 +1364,4 @@ BaseContent::cPCL()
}


OUString BaseContent::getKey()
{
    return m_aUncPath;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/file/bc.hxx b/ucb/source/ucp/file/bc.hxx
index 381880d..8de055b 100644
--- a/ucb/source/ucp/file/bc.hxx
+++ b/ucb/source/ucp/file/bc.hxx
@@ -264,7 +264,6 @@ namespace fileaccess {
        ContentEventNotifier*          cCEL() SAL_OVERRIDE;
        PropertySetInfoChangeNotifier* cPSL() SAL_OVERRIDE;
        PropertyChangeNotifier*        cPCL() SAL_OVERRIDE;
        OUString                  getKey() SAL_OVERRIDE;

    private:
        // Data members
diff --git a/ucb/source/ucp/file/filinl.hxx b/ucb/source/ucp/file/filinl.hxx
index b2db314..48e1e25 100644
--- a/ucb/source/ucp/file/filinl.hxx
+++ b/ucb/source/ucp/file/filinl.hxx
@@ -43,14 +43,6 @@ inline const sal_Int16& SAL_CALL shell::MyProperty::getAttributes() const
{
    return Attributes;
}
inline void SAL_CALL shell::MyProperty::setHandle( const sal_Int32& __Handle ) const
{
    const_cast<MyProperty*>(this)->Handle = __Handle;
}
inline void SAL_CALL shell::MyProperty::setType( const com::sun::star::uno::Type& __Typ ) const
{
    const_cast<MyProperty*>(this)->Typ = __Typ;
}
inline void SAL_CALL shell::MyProperty::setValue( const com::sun::star::uno::Any& __Value ) const
{
    const_cast<MyProperty*>(this)->Value = __Value;
@@ -59,11 +51,6 @@ inline void SAL_CALL shell::MyProperty::setState( const com::sun::star::beans::P
{
    const_cast<MyProperty*>(this)->State = __State;
}
inline void SAL_CALL shell::MyProperty::setAttributes( const sal_Int16& __Attributes ) const
{
    const_cast<MyProperty*>(this)->Attributes = __Attributes;
}


#endif

diff --git a/ucb/source/ucp/file/filnot.hxx b/ucb/source/ucp/file/filnot.hxx
index 327ec483..95db864 100644
--- a/ucb/source/ucp/file/filnot.hxx
+++ b/ucb/source/ucp/file/filnot.hxx
@@ -113,7 +113,6 @@ namespace fileaccess {
        virtual ContentEventNotifier*          cCEL() = 0;
        virtual PropertySetInfoChangeNotifier* cPSL() = 0;
        virtual PropertyChangeNotifier*        cPCL() = 0;
        virtual OUString                  getKey() = 0;

    protected:
        ~Notifier() {}
diff --git a/ucb/source/ucp/file/filrset.hxx b/ucb/source/ucp/file/filrset.hxx
index 625baad..a50645b 100644
--- a/ucb/source/ucp/file/filrset.hxx
+++ b/ucb/source/ucp/file/filrset.hxx
@@ -88,11 +88,6 @@ class XResultSet_impl : public Notifier,
            return 0;
        }

        virtual OUString                  getKey() SAL_OVERRIDE
        {
            return m_aBaseDirectory;
        }

        sal_Int32 SAL_CALL CtorSuccess() { return m_nErrorCode;}
        sal_Int32 SAL_CALL getMinorError() { return m_nMinorErrorCode;}

diff --git a/ucb/source/ucp/file/filtask.hxx b/ucb/source/ucp/file/filtask.hxx
index 928523d..d24aec4 100644
--- a/ucb/source/ucp/file/filtask.hxx
+++ b/ucb/source/ucp/file/filtask.hxx
@@ -112,15 +112,6 @@ namespace fileaccess
                return m_nMinorCode;
            }

            com::sun::star::uno::Reference< com::sun::star::ucb::XProgressHandler > SAL_CALL
            getProgressHandler()
            {
                if( ! m_xProgressHandler.is() && m_xCommandEnvironment.is() )
                    m_xProgressHandler = m_xCommandEnvironment->getProgressHandler();

                return m_xProgressHandler;
            }

            com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > SAL_CALL
            getInteractionHandler()
            {
@@ -167,8 +158,6 @@ namespace fileaccess
         *  The minor code refines the information given in ErrorCode.
         */

        void SAL_CALL clearError();

        void SAL_CALL installError( sal_Int32 CommandId,
                                    sal_Int32 ErrorCode,
                                    sal_Int32 minorCode = TASKHANDLER_NO_ERROR );
diff --git a/ucb/source/ucp/file/shell.hxx b/ucb/source/ucp/file/shell.hxx
index fc9de68..2a05712 100644
--- a/ucb/source/ucp/file/shell.hxx
+++ b/ucb/source/ucp/file/shell.hxx
@@ -107,11 +107,8 @@ namespace fileaccess {
            inline const sal_Int16& SAL_CALL getAttributes() const;

            // The set* functions are declared const, because the key of "this" stays intact
            inline void SAL_CALL setHandle( const sal_Int32&  __Handle ) const;
            inline void SAL_CALL setType( const com::sun::star::uno::Type& __Type ) const;
            inline void SAL_CALL setValue( const com::sun::star::uno::Any& __Value ) const;
            inline void SAL_CALL setState( const com::sun::star::beans::PropertyState& __State ) const;
            inline void SAL_CALL setAttributes( const sal_Int16& __Attributes ) const;
        };

        struct eMyProperty
@@ -500,12 +497,6 @@ namespace fileaccess {
            const com::sun::star::uno::Sequence< com::sun::star::beans::Property >& seq );


        void SAL_CALL
        setFileProperties(
            const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& values,
            sal_Int32 numberOfValues );


        // Helper function for public copy

        osl::FileBase::RC SAL_CALL
diff --git a/ucb/source/ucp/ftp/ftpcfunc.hxx b/ucb/source/ucp/ftp/ftpcfunc.hxx
index c20ef0b..f7899ed 100644
--- a/ucb/source/ucp/ftp/ftpcfunc.hxx
+++ b/ucb/source/ucp/ftp/ftpcfunc.hxx
@@ -32,9 +32,6 @@ namespace ftp {

    class FTPStreamContainer
    {
    public:
        virtual size_t write(void *buffer,size_t size,size_t nmemb) = 0;

    protected:
        ~FTPStreamContainer() {}
    };
diff --git a/ucb/source/ucp/ftp/ftpdirp.hxx b/ucb/source/ucp/ftp/ftpdirp.hxx
index 676a506..5a6d2dc 100644
--- a/ucb/source/ucp/ftp/ftpdirp.hxx
+++ b/ucb/source/ucp/ftp/ftpdirp.hxx
@@ -104,14 +104,6 @@ namespace ftp {
            m_nMode = INETCOREFTP_FILEMODE_UNKNOWN;
            m_nSize = sal_uInt32(-1);
        }

        bool isDir() const {
            return (m_nMode & INETCOREFTP_FILEMODE_ISDIR) != 0;
        }

        bool isFile() const {
            return (m_nMode & INETCOREFTP_FILEMODE_ISDIR) == 0;
        }
    };


diff --git a/ucb/source/ucp/ftp/ftpstrcont.hxx b/ucb/source/ucp/ftp/ftpstrcont.hxx
index 00efa78..383995c 100644
--- a/ucb/source/ucp/ftp/ftpstrcont.hxx
+++ b/ucb/source/ucp/ftp/ftpstrcont.hxx
@@ -32,25 +32,18 @@

namespace ftp {


    class FTPInputStream;


    class FTPOutputStreamContainer
        : public FTPStreamContainer
    {
    public:

        explicit FTPOutputStreamContainer(const com::sun::star::uno::Reference<
                                 com::sun::star::io::XOutputStream>& out);

        virtual ~FTPOutputStreamContainer() {}

        virtual size_t write(void *buffer,size_t size,size_t nmemb) SAL_OVERRIDE;


    private:

        com::sun::star::uno::Reference<
        com::sun::star::io::XOutputStream> m_out;
    };
@@ -60,22 +53,17 @@ namespace ftp {
        : public FTPStreamContainer
    {
    public:

        explicit FTPInputStreamContainer(FTPInputStream* out);

        virtual ~FTPInputStreamContainer() {}

        virtual size_t write(void *buffer,size_t size,size_t nmemb) SAL_OVERRIDE;

        com::sun::star::uno::Reference<
        com::sun::star::io::XInputStream> operator()();

    private:

        FTPInputStream* m_out;
    };


}


diff --git a/ucb/source/ucp/gio/gio_content.hxx b/ucb/source/ucp/gio/gio_content.hxx
index c4ce79e..6055b6b 100644
--- a/ucb/source/ucp/gio/gio_content.hxx
+++ b/ucb/source/ucp/gio/gio_content.hxx
@@ -113,10 +113,6 @@ private:
    bool feedSink( com::sun::star::uno::Reference< com::sun::star::uno::XInterface> aSink,
        const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
        createInputStream(const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv )
            throw( com::sun::star::uno::Exception );

    bool exchangeIdentity(const com::sun::star::uno::Reference< com::sun::star::ucb::XContentIdentifier >&  xNewId);

public:
diff --git a/ucb/source/ucp/hierarchy/hierarchyuri.hxx b/ucb/source/ucp/hierarchy/hierarchyuri.hxx
index 2a6be25..75f9bc6 100644
--- a/ucb/source/ucp/hierarchy/hierarchyuri.hxx
+++ b/ucb/source/ucp/hierarchy/hierarchyuri.hxx
@@ -54,9 +54,6 @@ public:
    const OUString & getUri() const
    { init(); return m_aUri; }

    void setUri( const OUString & rUri )
    { m_aPath.clear(); m_aUri = rUri; m_bValid = false; }

    const OUString & getParentUri() const
    { init(); return m_aParentUri; }

@@ -66,9 +63,6 @@ public:
    const OUString & getPath() const
    { init(); return m_aPath; }

    const OUString & getName() const
    { init(); return m_aName; }

    inline bool isRootFolder() const;
};

diff --git a/ucb/source/ucp/tdoc/tdoc_uri.hxx b/ucb/source/ucp/tdoc/tdoc_uri.hxx
index d4ecdd2..12d40e4 100644
--- a/ucb/source/ucp/tdoc/tdoc_uri.hxx
+++ b/ucb/source/ucp/tdoc/tdoc_uri.hxx
@@ -69,15 +69,9 @@ public:
    const OUString & getParentUri() const
    { init(); return m_aParentUri; }

    const OUString & getPath() const
    { init(); return m_aPath; }

    const OUString & getDocumentId() const
    { init(); return m_aDocId; }

    const OUString & getInternalPath() const
    { init(); return m_aInternalPath; }

    const OUString & getName() const
    { init(); return m_aName; }

@@ -87,8 +81,6 @@ public:
    inline bool isRoot() const;

    inline bool isDocument() const;

    inline bool isFolder() const;
};

inline void Uri::setUri( const OUString & rUri )
@@ -116,12 +108,6 @@ inline bool Uri::isDocument() const
             && ( m_aPath.copy( m_aDocId.getLength() + 1 ).getLength() < 2 ) );
}

inline bool Uri::isFolder() const
{
    init();
    return m_aPath.isEmpty() || m_aPath.endsWith( "/" );
}

} // namespace tdoc_ucp

#endif // INCLUDED_UCB_SOURCE_UCP_TDOC_TDOC_URI_HXX
diff --git a/ucb/source/ucp/webdav-neon/DAVSession.hxx b/ucb/source/ucp/webdav-neon/DAVSession.hxx
index d700b1b..8180507 100644
--- a/ucb/source/ucp/webdav-neon/DAVSession.hxx
+++ b/ucb/source/ucp/webdav-neon/DAVSession.hxx
@@ -75,12 +75,6 @@ public:

    // DAV methods


    virtual void OPTIONS( const OUString & inPath,
                          DAVCapabilities & outCapabilities,
                          const DAVRequestEnvironment & rEnv )
        throw( std::exception ) = 0;

    // allprop & named
    virtual void PROPFIND( const OUString & inPath,
                           const Depth inDepth,
@@ -184,12 +178,6 @@ public:
                       const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) = 0;

    // refresh existing lock.
    virtual sal_Int64 LOCK( const OUString & inPath,
                            sal_Int64 nTimeout,
                            const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) = 0;

    virtual void UNLOCK( const OUString & inPath,
                         const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) = 0;
diff --git a/ucb/source/ucp/webdav-neon/NeonSession.cxx b/ucb/source/ucp/webdav-neon/NeonSession.cxx
index c70bc1b..8deb3dc 100644
--- a/ucb/source/ucp/webdav-neon/NeonSession.cxx
+++ b/ucb/source/ucp/webdav-neon/NeonSession.cxx
@@ -824,30 +824,6 @@ bool NeonSession::UsesProxy()
    return  !m_aProxyName.isEmpty() ;
}

void NeonSession::OPTIONS( const OUString & inPath,
                           DAVCapabilities & outCapabilities,
                           const DAVRequestEnvironment & rEnv )
    throw( std::exception )
{
    osl::Guard< osl::Mutex > theGuard( m_aMutex );

    Init( rEnv );

    HttpServerCapabilities servercaps;
    memset( &servercaps, 0, sizeof( servercaps ) );

    int theRetVal = ne_options( m_pHttpSession,
                                OUStringToOString(
                                    inPath, RTL_TEXTENCODING_UTF8 ).getStr(),
                                &servercaps );

    HandleError( theRetVal, inPath, rEnv );

    outCapabilities.class1     = !!servercaps.dav_class1;
    outCapabilities.class2     = !!servercaps.dav_class2;
    outCapabilities.executable = !!servercaps.dav_executable;
}

void NeonSession::PROPFIND( const OUString & inPath,
                            const Depth inDepth,
                            const std::vector< OUString > & inPropNames,
@@ -1425,42 +1401,6 @@ void NeonSession::LOCK( const OUString & inPath,
}

// Refresh existing lock
sal_Int64 NeonSession::LOCK( const OUString & inPath,
                             sal_Int64 nTimeout,
                             const DAVRequestEnvironment & rEnv )
    throw ( std::exception )
{
    osl::Guard< osl::Mutex > theGuard( m_aMutex );

    // Try to get the neon lock from lock store
    NeonLock * theLock
        = m_aNeonLockStore.findByUri( makeAbsoluteURL( inPath ) );
    if ( !theLock )
         throw DAVException( DAVException::DAV_NOT_LOCKED );

    Init( rEnv );

    // refresh existing lock.
    theLock->timeout = static_cast< long >( nTimeout );

    TimeValue startCall;
    osl_getSystemTime( &startCall );

    int theRetVal = ne_lock_refresh( m_pHttpSession, theLock );

    if ( theRetVal == NE_OK )
    {
        m_aNeonLockStore.updateLock( theLock,
                                     lastChanceToSendRefreshRequest(
                                         startCall, theLock->timeout ) );
    }

    HandleError( theRetVal, inPath, rEnv );

    return theLock->timeout;
}

// Refresh existing lock
bool NeonSession::LOCK( NeonLock * pLock,
                        sal_Int32 & rlastChanceToSendRefreshRequest )
{
diff --git a/ucb/source/ucp/webdav-neon/NeonSession.hxx b/ucb/source/ucp/webdav-neon/NeonSession.hxx
index fb03927..3b113ad 100644
--- a/ucb/source/ucp/webdav-neon/NeonSession.hxx
+++ b/ucb/source/ucp/webdav-neon/NeonSession.hxx
@@ -86,12 +86,6 @@ public:
    const DAVRequestEnvironment & getRequestEnvironment() const
    { return m_aEnv; }

    virtual void
    OPTIONS( const OUString &  inPath,
             DAVCapabilities & outCapabilities,
             const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) SAL_OVERRIDE;

    // allprop & named
    virtual void
    PROPFIND( const OUString & inPath,
@@ -206,12 +200,6 @@ public:
                       const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) SAL_OVERRIDE;

    // refresh existing lock.
    virtual sal_Int64 LOCK( const OUString & inURL,
                            sal_Int64 nTimeout,
                            const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) SAL_OVERRIDE;

    virtual void UNLOCK( const OUString & inURL,
                         const DAVRequestEnvironment & rEnv )
        throw ( std::exception ) SAL_OVERRIDE;
diff --git a/ucb/source/ucp/webdav-neon/NeonUri.hxx b/ucb/source/ucp/webdav-neon/NeonUri.hxx
index 9fedb88..cd9fbe9 100644
--- a/ucb/source/ucp/webdav-neon/NeonUri.hxx
+++ b/ucb/source/ucp/webdav-neon/NeonUri.hxx
@@ -92,8 +92,6 @@ class NeonUri
        static OUString makeConnectionEndPointString(
                                        const OUString & rHostName,
                                        int nPort );
        OUString makeConnectionEndPointString() const
        { return makeConnectionEndPointString( GetHost(), GetPort() ); }
};

} // namespace webdav_ucp
diff --git a/ucb/source/ucp/webdav-neon/webdavprovider.hxx b/ucb/source/ucp/webdav-neon/webdavprovider.hxx
index 66eea5d..a93f752 100644
--- a/ucb/source/ucp/webdav-neon/webdavprovider.hxx
+++ b/ucb/source/ucp/webdav-neon/webdavprovider.hxx
@@ -129,13 +129,8 @@ public:
    // Additional interfaces



    // Non-interface methods.


    rtl::Reference< DAVSessionFactory > getDAVSessionFactory()
    { return m_xDAVSessionFactory; }

    bool getProperty( const OUString & rPropName,
                      ::com::sun::star::beans::Property & rProp,
                      bool bStrict = false );