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
|
/* -*- 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 "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 )
{
compiler.getPreprocessor().addPPCallbacks( 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 )
{
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 ))
{
// 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* )
#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* )
#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* )
#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 )
#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: */
|