From 1e313e759b79bd55d977156483847e22273d8e65 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Sat, 13 Oct 2012 17:38:58 +0200 Subject: compiler check to compare SAL_WARN/LOG areas against sal/inc/sal/log-areas.dox Some of the areas are guesses I've added after seeing them, whoever feels reponsible for whichever part of the code feel free to adjust them. Change-Id: I2192de84d51cc2bc7c28fa84019d38b465985d15 --- compilerplugins/Makefile-clang.mk | 3 +- compilerplugins/clang/compileplugin.cxx | 9 +- compilerplugins/clang/compileplugin.hxx | 2 +- compilerplugins/clang/sallogareas.cxx | 113 ++++++++++++++++++++++++++ compilerplugins/clang/sallogareas.hxx | 39 +++++++++ compilerplugins/clang/unusedvariablecheck.cxx | 7 +- compilerplugins/clang/unusedvariablecheck.hxx | 2 +- 7 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 compilerplugins/clang/sallogareas.cxx create mode 100644 compilerplugins/clang/sallogareas.hxx (limited to 'compilerplugins') diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk index e9192fe4a1ac..f9bec4147084 100644 --- a/compilerplugins/Makefile-clang.mk +++ b/compilerplugins/Makefile-clang.mk @@ -11,6 +11,7 @@ # The list of source files. CLANGSRC=compileplugin.cxx \ bodynotinblock.cxx \ + sallogareas.cxx \ unusedvariablecheck.cxx \ @@ -52,7 +53,7 @@ CLANGOBJS= define clangbuildsrc $(3): $(2) $(SRCDIR)/compilerplugins/Makefile-clang.mk $(CLANGOUTDIR)/clang-timestamp @echo [build CXX] $(subst $(SRCDIR)/,,$(2)) - $(CXX) $(CLANGCXXFLAGS) $(CLANGDEFS) $(CLANGINCLUDES) $(2) -fPIC -c -o $(3) -MMD -MT $(3) -MP -MF $(CLANGOUTDIR)/$(1).d + $(CXX) $(CLANGCXXFLAGS) $(CLANGDEFS) $(CLANGINCLUDES) -DSRCDIR=$(SRCDIR) $(2) -fPIC -c -o $(3) -MMD -MT $(3) -MP -MF $(CLANGOUTDIR)/$(1).d -include $(CLANGOUTDIR)/$(1).d diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx index a61a3bab66a4..c243b7a24baa 100644 --- a/compilerplugins/clang/compileplugin.cxx +++ b/compilerplugins/clang/compileplugin.cxx @@ -18,6 +18,7 @@ #include #include "bodynotinblock.hxx" +#include "sallogareas.hxx" #include "unusedvariablecheck.hxx" using namespace clang; @@ -40,7 +41,10 @@ DiagnosticBuilder Plugin::report( DiagnosticsEngine::Level level, StringRef mess if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal()) level = DiagnosticsEngine::Fatal; #endif - return diag.Report( loc, diag.getCustomDiagID( level, message )); + if( loc.isValid()) + return diag.Report( loc, diag.getCustomDiagID( level, message )); + else + return diag.Report( diag.getCustomDiagID( level, message )); } bool Plugin::ignoreLocation( SourceLocation loc ) @@ -58,6 +62,7 @@ class PluginHandler explicit PluginHandler( ASTContext& context ) : rewriter( context.getSourceManager(), context.getLangOpts()) , bodyNotInBlock( context ) + , salLogAreas( context ) , unusedVariableCheck( context ) { } @@ -66,6 +71,7 @@ class PluginHandler if( context.getDiagnostics().hasErrorOccurred()) return; bodyNotInBlock.run(); + salLogAreas.run(); unusedVariableCheck.run(); // TODO also LO header files? or a subdir? if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID())) @@ -75,6 +81,7 @@ class PluginHandler private: Rewriter rewriter; BodyNotInBlock bodyNotInBlock; + SalLogAreas salLogAreas; UnusedVariableCheck unusedVariableCheck; }; diff --git a/compilerplugins/clang/compileplugin.hxx b/compilerplugins/clang/compileplugin.hxx index 6c854d1e0179..c8ad29641b14 100644 --- a/compilerplugins/clang/compileplugin.hxx +++ b/compilerplugins/clang/compileplugin.hxx @@ -23,7 +23,7 @@ class Plugin public: explicit Plugin( ASTContext& context ); protected: - DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc ); + DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc = SourceLocation()); bool ignoreLocation( SourceLocation loc ); bool ignoreLocation( const Decl* decl ); bool ignoreLocation( const Stmt* stmt ); diff --git a/compilerplugins/clang/sallogareas.cxx b/compilerplugins/clang/sallogareas.cxx new file mode 100644 index 000000000000..b7c2f2263931 --- /dev/null +++ b/compilerplugins/clang/sallogareas.cxx @@ -0,0 +1,113 @@ +/* + * 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 "sallogareas.hxx" + +#include + +#include + +using namespace std; + +namespace loplugin +{ + +/* +Check that areas used in SAL_LOG/SAL_WARN are listed in sal/inc/sal/log-areas.dox . +*/ + +SalLogAreas::SalLogAreas( ASTContext& context ) + : Plugin( context ) + { + } + +void SalLogAreas::run() + { + inFunction = NULL; + TraverseDecl( context.getTranslationUnitDecl()); + } + +bool SalLogAreas::VisitFunctionDecl( FunctionDecl* function ) + { + inFunction = function; + return true; + } + +bool SalLogAreas::VisitCallExpr( CallExpr* call ) + { + if( ignoreLocation( call )) + return true; + if( FunctionDecl* func = call->getDirectCallee()) + { + // Optimize, getQualifiedNameAsString() is reportedly expensive. + if( func->getNumParams() == 4 && func->getIdentifier() != NULL + && ( func->getName() == "sal_detail_log" || func->getName() == "log" )) + { + std::string qualifiedName = func->getQualifiedNameAsString(); + if( qualifiedName == "sal_detail_log" || qualifiedName == "sal::detail::log" ) + { + if( const StringLiteral* area = dyn_cast< StringLiteral >( call->getArg( 1 )->IgnoreParenImpCasts())) + { + if( area->getKind() == StringLiteral::Ascii ) + checkArea( area->getBytes(), area->getExprLoc()); + else + report( DiagnosticsEngine::Warning, "unsupported string literal kind (plugin needs fixing?) [loplugin] sallog", + area->getLocStart()); + return true; + } + if( inFunction->getQualifiedNameAsString() == "sal::detail::log" ) + return true; // This function only forwards to sal_detail_log, so ok. + report( DiagnosticsEngine::Warning, "cannot analyse log area argument (plugin needs fixing?) [loplugin] sallog", + call->getLocStart()); + } + } + } + return true; + } + +void SalLogAreas::checkArea( StringRef area, SourceLocation location ) + { + if( logAreas.empty()) + readLogAreas(); + if( !logAreas.count( area )) + { + report( DiagnosticsEngine::Warning, "unknown log area '%0' (check or extend sal/inc/sal/log-areas.dox) [loplugin] sallog", + location ) << area; + } + } + +void SalLogAreas::readLogAreas() + { +#define STRINGIFY2( s ) #s +#define STRINGIFY( s ) STRINGIFY2( s ) + ifstream is( STRINGIFY( SRCDIR ) "/sal/inc/sal/log-areas.dox" ); +#undef STRINGIFY +#undef STRINGIFY2 + while( is.good()) + { + string line; + getline( is, line ); + size_t pos = line.find( "@li @c " ); + if( pos != string::npos ) + { + pos += strlen( "@li @c " ); + size_t end = line.find( ' ', pos ); + if( end == string::npos ) + logAreas.insert( line.substr( pos )); + else if( pos != end ) + logAreas.insert( line.substr( pos, end - pos )); + } + } + // If you get this error message, you possibly have too old icecream (ICECC_EXTRAFILES is needed). + if( logAreas.empty()) + report( DiagnosticsEngine::Warning, "error reading log areas [loplugin] sallog" ); + } + +} // namespace diff --git a/compilerplugins/clang/sallogareas.hxx b/compilerplugins/clang/sallogareas.hxx new file mode 100644 index 000000000000..520762973743 --- /dev/null +++ b/compilerplugins/clang/sallogareas.hxx @@ -0,0 +1,39 @@ +/* + * 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. + * + */ + +#ifndef SALLOGAREAS_H +#define SALLOGAREAS_H + +#include + +#include "compileplugin.hxx" + +namespace loplugin +{ + +class SalLogAreas + : public RecursiveASTVisitor< SalLogAreas > + , public Plugin + { + public: + explicit SalLogAreas( ASTContext& context ); + void run(); + bool VisitFunctionDecl( FunctionDecl* function ); + bool VisitCallExpr( CallExpr* call ); + private: + void checkArea( StringRef area, SourceLocation location ); + void readLogAreas(); + const FunctionDecl* inFunction; + std::set< std::string > logAreas; + }; + +} // namespace + +#endif // SALLOGAREAS_H diff --git a/compilerplugins/clang/unusedvariablecheck.cxx b/compilerplugins/clang/unusedvariablecheck.cxx index 3d9ca3de0513..733c2be42d78 100644 --- a/compilerplugins/clang/unusedvariablecheck.cxx +++ b/compilerplugins/clang/unusedvariablecheck.cxx @@ -38,13 +38,10 @@ void UnusedVariableCheck::run() TraverseDecl( context.getTranslationUnitDecl()); } -bool UnusedVariableCheck::VisitNamedDecl( NamedDecl* declaration ) +bool UnusedVariableCheck::VisitVarDecl( VarDecl* var ) { - if( ignoreLocation( declaration )) + if( ignoreLocation( var )) return true; - if( !isa< VarDecl >( declaration )) - return true; - const VarDecl* var = cast< VarDecl >( declaration ); if( var->isReferenced() || var->isUsed()) return true; if( var->isDefinedOutsideFunctionOrMethod()) diff --git a/compilerplugins/clang/unusedvariablecheck.hxx b/compilerplugins/clang/unusedvariablecheck.hxx index 21e0eabd03c0..3099eec39522 100644 --- a/compilerplugins/clang/unusedvariablecheck.hxx +++ b/compilerplugins/clang/unusedvariablecheck.hxx @@ -23,7 +23,7 @@ class UnusedVariableCheck public: explicit UnusedVariableCheck( ASTContext& context ); void run(); - bool VisitNamedDecl( NamedDecl* declaration ); + bool VisitVarDecl( VarDecl* var ); }; } // namespace -- cgit