# Cppcheck report - LibreOffice: compilerplugins/clang/checkconfigmacros.cxx

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142

    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * Based on LLVM/Clang.
     *
     * This file is distributed under the University of Illinois Open Source
     * License. See LICENSE.TXT for details.
     *
     */

    #include "compat.hxx"
    #include "plugin.hxx"

    #include <clang/Lex/Preprocessor.h>

    namespace loplugin
    {

    /*
    This is a compile check.

    Feature macros from config_XXX.h headers are always #defined (to 1 or 0 in case of yes/no
    settings). It is a mistake to use #ifdef/#ifndef/defined to check them.

    Using 1/0 instead of defined/undefined avoids undetected problems when e.g. the necessary
    #include of the config_XXX.h file is missing.
    */

    class CheckConfigMacros
        : public PPCallbacks
        , public Plugin
        {
        public:
            explicit CheckConfigMacros( const InstantiationData& data );
            virtual void run() override;
    #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
            virtual void MacroDefined( const Token& macroToken, const MacroInfo* info ) override;
            virtual void MacroUndefined( const Token& macroToken, const MacroInfo* info ) override;
            virtual void Ifdef( SourceLocation location, const Token& macroToken ) override;
            virtual void Ifndef( SourceLocation location, const Token& macroToken ) override;
            virtual void Defined( const Token& macroToken ) override;
    #else
            virtual void MacroDefined( const Token& macroToken, const MacroDirective* info ) override;
            virtual void MacroUndefined( const Token& macroToken, const MacroDirective* info ) override;
            virtual void Ifdef( SourceLocation location, const Token& macroToken, const MacroDirective* info ) override;
            virtual void Ifndef( SourceLocation location, const Token& macroToken, const MacroDirective* info ) override;
    #if __clang_major__ == 3 && __clang_minor__ < 4
            virtual void Defined( const Token& macroToken, const MacroDirective* info ) override;
    #else
            virtual void Defined( const Token& macroToken, const MacroDirective* info, SourceRange Range ) override;
    #endif
    #endif
            enum { isPPCallback = true };
        private:
            void checkMacro( const Token& macroToken, SourceLocation location );
            std::set< string > configMacros;
        };

    CheckConfigMacros::CheckConfigMacros( const InstantiationData& data )
        : Plugin( data )
        {
        compat::addPPCallbacks(compiler.getPreprocessor(), this);
        }

    void CheckConfigMacros::run()
        {
        // nothing, only check preprocessor usage
        }

    #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
    void CheckConfigMacros::MacroDefined( const Token& macroToken, const MacroInfo* info )
        {
        SourceLocation location = info->getDefinitionLoc();
    #else
    void CheckConfigMacros::MacroDefined( const Token& macroToken, const MacroDirective* info )<--- The function 'MacroDefined' is never used.
        {
        SourceLocation location = info->getLocation();
    #endif
        const char* filename = compiler.getSourceManager().getPresumedLoc( location ).getFilename();
        if( filename != NULL
            && ( strncmp( filename, BUILDDIR "/config_host/", strlen( BUILDDIR "/config_host/" )) == 0
                || strncmp( filename, BUILDDIR "/config_build/", strlen( BUILDDIR "/config_build/" )) == 0 ))<--- Same expression on both sides of '||'.
            {
    //        fprintf(stderr,"DEF: %s %s\n", macroToken.getIdentifierInfo()->getName().data(), filename );
            configMacros.insert( macroToken.getIdentifierInfo()->getName());
            }
        }

    #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
    void CheckConfigMacros::MacroUndefined( const Token& macroToken, const MacroInfo* )
    #else
    void CheckConfigMacros::MacroUndefined( const Token& macroToken, const MacroDirective* )<--- The function 'MacroUndefined' is never used.
    #endif
        {
        configMacros.erase( macroToken.getIdentifierInfo()->getName());
        }

    #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
    void CheckConfigMacros::Ifdef( SourceLocation location, const Token& macroToken )
    #else
    void CheckConfigMacros::Ifdef( SourceLocation location, const Token& macroToken, const MacroDirective* )<--- The function 'Ifdef' is never used.
    #endif
        {
        checkMacro( macroToken, location );
        }

    #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
    void CheckConfigMacros::Ifndef( SourceLocation location, const Token& macroToken )
    #else
    void CheckConfigMacros::Ifndef( SourceLocation location, const Token& macroToken, const MacroDirective* )<--- The function 'Ifndef' is never used.
    #endif
        {
        checkMacro( macroToken, location );
        }

    #if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
    void CheckConfigMacros::Defined( const Token& macroToken )
    #elif __clang_major__ == 3 && __clang_minor__ < 4
    void CheckConfigMacros::Defined( const Token& macroToken, const MacroDirective* )
    #else
    void CheckConfigMacros::Defined( const Token& macroToken, const MacroDirective* , SourceRange )<--- The function 'Defined' is never used.
    #endif
        {
        checkMacro( macroToken, macroToken.getLocation());
        }

    void CheckConfigMacros::checkMacro( const Token& macroToken, SourceLocation location )
        {
        if( configMacros.find( macroToken.getIdentifierInfo()->getName()) != configMacros.end())
            {
            report( DiagnosticsEngine::Error, "checking whether a config macro %0 is defined",
                location ) << macroToken.getIdentifierInfo()->getName();
            report( DiagnosticsEngine::Note, "use #if instead of #ifdef/#ifndef/defined", location );
            }
        }

    static Plugin::Registration< CheckConfigMacros > X( "bodynotinblock" );

    } // namespace

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */