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:
Luboš Luňák
2012-10-09 14:50:19 +02:00
parent 02a8d36ebf
commit 13e39545ea
6 changed files with 180 additions and 1 deletions

View File

@@ -9,7 +9,7 @@
# Make sure variables in this Makefile do not conflict with other variables (e.g. from gbuild).
# The list of source files.
CLANGSRC=compileplugin.cxx
CLANGSRC=compileplugin.cxx unusedvariablecheck.cxx
# You may occassionally want to override some of these

View File

@@ -21,6 +21,13 @@ are found or explicitly using --enable-compiler-plugins.
The compile plugin is used during normal compilation to perform additional checks.
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 ==

View File

@@ -17,6 +17,8 @@
#include <clang/Frontend/FrontendPluginRegistry.h>
#include <clang/Rewrite/Rewriter.h>
#include "unusedvariablecheck.hxx"
using namespace clang;
namespace loplugin
@@ -31,12 +33,14 @@ class PluginHandler
public:
explicit PluginHandler( ASTContext& context )
: rewriter( context.getSourceManager(), context.getLangOpts())
, unusedVariableCheck( context )
{
}
virtual void HandleTranslationUnit( ASTContext& context )
{
if( context.getDiagnostics().hasErrorOccurred())
return;
unusedVariableCheck.run();
// TODO also LO header files? or a subdir?
if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID()))
buf->write( llvm::outs());
@@ -44,6 +48,7 @@ class PluginHandler
}
private:
Rewriter rewriter;
UnusedVariableCheck unusedVariableCheck;
};
/**

View 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

View 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

View File

@@ -489,6 +489,26 @@ template< typename T1, typename T2 > inline T1 static_int_cast(T2 n) {
#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_ */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */