Kaydet (Commit) 13e39545 authored tarafından Luboš Luňák's avatar Luboš Luňák

compiler check for unused variables

This is for variables that the compiler itself cannot figure out
(e.g. non-trivial ctors). The classes need to be marked manually.

Change-Id: I0109972e11e20578b1adc32065f701a871ee21aa
üst 02a8d36e
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# Make sure variables in this Makefile do not conflict with other variables (e.g. from gbuild). # Make sure variables in this Makefile do not conflict with other variables (e.g. from gbuild).
# The list of source files. # The list of source files.
CLANGSRC=compileplugin.cxx CLANGSRC=compileplugin.cxx unusedvariablecheck.cxx
# You may occassionally want to override some of these # You may occassionally want to override some of these
......
...@@ -21,6 +21,13 @@ are found or explicitly using --enable-compiler-plugins. ...@@ -21,6 +21,13 @@ are found or explicitly using --enable-compiler-plugins.
The compile plugin is used during normal compilation to perform additional checks. The compile plugin is used during normal compilation to perform additional checks.
All warnings and errors are marked '[loplugin]' in the message. All warnings and errors are marked '[loplugin]' in the message.
==== Unused variable check ====
- unused parameter 'foo' [loplugin]
- unused variable 'foo' [loplugin]
Additional check for unused variables.
== Code documentation / howtos == == Code documentation / howtos ==
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <clang/Frontend/FrontendPluginRegistry.h> #include <clang/Frontend/FrontendPluginRegistry.h>
#include <clang/Rewrite/Rewriter.h> #include <clang/Rewrite/Rewriter.h>
#include "unusedvariablecheck.hxx"
using namespace clang; using namespace clang;
namespace loplugin namespace loplugin
...@@ -31,12 +33,14 @@ class PluginHandler ...@@ -31,12 +33,14 @@ class PluginHandler
public: public:
explicit PluginHandler( ASTContext& context ) explicit PluginHandler( ASTContext& context )
: rewriter( context.getSourceManager(), context.getLangOpts()) : rewriter( context.getSourceManager(), context.getLangOpts())
, unusedVariableCheck( context )
{ {
} }
virtual void HandleTranslationUnit( ASTContext& context ) virtual void HandleTranslationUnit( ASTContext& context )
{ {
if( context.getDiagnostics().hasErrorOccurred()) if( context.getDiagnostics().hasErrorOccurred())
return; return;
unusedVariableCheck.run();
// TODO also LO header files? or a subdir? // TODO also LO header files? or a subdir?
if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID())) if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID()))
buf->write( llvm::outs()); buf->write( llvm::outs());
...@@ -44,6 +48,7 @@ class PluginHandler ...@@ -44,6 +48,7 @@ class PluginHandler
} }
private: private:
Rewriter rewriter; Rewriter rewriter;
UnusedVariableCheck unusedVariableCheck;
}; };
/** /**
......
/*
* 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 "unusedvariablecheck.hxx"
#include <clang/Basic/SourceManager.h>
using namespace clang;
namespace loplugin
{
/*
Check for unused classes where the compiler cannot decide (e.g. because of
non-trivial or extern ctors) if a variable is unused if only its ctor/dtor
are called and nothing else. For example std::vector is a class where
the ctor may call further functions, but an unused std::string variable
does nothing. On the other hand, std::auto_ptr instances are used
for their dtors and so are not unused even if not otherwise accessed.
Classes which are safe to be warned about need to be marked using
SAL_WARN_UNUSED (see e.g. OUString). For external classes such as std::vector
that cannot be edited there is a manual list below.
*/
UnusedVariableCheck::UnusedVariableCheck( ASTContext& context )
: context( context )
{
}
void UnusedVariableCheck::run()
{
TraverseDecl( context.getTranslationUnitDecl());
}
DiagnosticBuilder UnusedVariableCheck::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
{
// Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
DiagnosticsEngine& diag = context.getDiagnostics();
if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
level = DiagnosticsEngine::Error;
if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
level = DiagnosticsEngine::Fatal;
return diag.Report( loc, diag.getCustomDiagID( level, message ));
}
bool UnusedVariableCheck::VisitNamedDecl( NamedDecl* declaration )
{
// TODO also LO header files? or a subdir?
if( !context.getSourceManager().isFromMainFile( declaration->getLocStart()))
return true;
if( !isa< VarDecl >( declaration ))
return true;
const VarDecl* var = cast< VarDecl >( declaration );
if( var->isReferenced() || var->isUsed())
return true;
if( CXXRecordDecl* type = var->getType()->getAsCXXRecordDecl())
{
bool warn_unused = false;
if( type->hasAttrs())
{
// Clang currently has no support for custom attributes, but
// the annotate attribute comes close, so check for __attribute__((annotate("lo_warn_unused")))
for( specific_attr_iterator<AnnotateAttr> i = type->specific_attr_begin<AnnotateAttr>(),
e = type->specific_attr_end<AnnotateAttr>();
i != e;
++i )
{
if( (*i)->getAnnotation() == "lo_warn_unused" )
{
warn_unused = true;
break;
}
}
}
if( !warn_unused )
{
std::string n = type->getQualifiedNameAsString();
// Check some common non-LO types.
if( n == "std::string" || n == "std::basic_string"
|| n == "std::list" || n == "std::__debug::list"
|| n == "std::vector" || n == "std::__debug::vector" )
warn_unused = true;
}
if( warn_unused )
{
if( const ParmVarDecl* param = dyn_cast< ParmVarDecl >( var ))
{
// If this declaration does not have a body, then the parameter is indeed not used,
// so ignore.
if( const FunctionDecl* func = dyn_cast< FunctionDecl >( param->getParentFunctionOrMethod()))
if( !func->doesThisDeclarationHaveABody())
return true;
report( DiagnosticsEngine::Warning, "unused parameter %0 [loplugin]",
var->getLocStart()) << var->getDeclName();
}
else
report( DiagnosticsEngine::Warning, "unused variable %0 [loplugin]",
var->getLocStart()) << var->getDeclName();
}
}
return true;
}
} // namespace
/*
* 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 UNUSEDVARIABLECHECK_H
#define UNUSEDVARIABLECHECK_H
#include <clang/AST/RecursiveASTVisitor.h>
using namespace clang;
namespace loplugin
{
class UnusedVariableCheck
: public RecursiveASTVisitor< UnusedVariableCheck >
{
public:
explicit UnusedVariableCheck( ASTContext& context );
void run();
bool VisitNamedDecl( NamedDecl* declaration );
private:
DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
ASTContext& context;
};
} // namespace
#endif // UNUSEDVARIABLECHECK_H
...@@ -489,6 +489,26 @@ template< typename T1, typename T2 > inline T1 static_int_cast(T2 n) { ...@@ -489,6 +489,26 @@ template< typename T1, typename T2 > inline T1 static_int_cast(T2 n) {
#endif #endif
#endif #endif
/**
Annotate classes where a compiler should warn if an instance is unused.
The compiler cannot warn about unused instances if they have non-trivial
or external constructors or destructors. Classes marked with SAL_WARN_UNUSED
will be warned about.
Currently implemented by a Clang compiler plugin.
@since LibreOffice 3.7
*/
#if defined __clang__
#define SAL_WARN_UNUSED __attribute__((annotate("lo_warn_unused")))
#else
#define SAL_WARN_UNUSED
#endif
#endif /*_SAL_TYPES_H_ */ #endif /*_SAL_TYPES_H_ */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment