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
This commit is contained in:
@@ -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.
|
|||||||
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 @@
|
|||||||
#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
|
|||||||
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
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Rewriter rewriter;
|
Rewriter rewriter;
|
||||||
|
UnusedVariableCheck unusedVariableCheck;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
112
compilerplugins/clang/unusedvariablecheck.cxx
Normal file
112
compilerplugins/clang/unusedvariablecheck.cxx
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
35
compilerplugins/clang/unusedvariablecheck.hxx
Normal file
35
compilerplugins/clang/unusedvariablecheck.hxx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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) {
|
|||||||
#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: */
|
||||||
|
Reference in New Issue
Block a user