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).
|
||||
|
||||
# The list of source files.
|
||||
CLANGSRC=compileplugin.cxx
|
||||
CLANGSRC=compileplugin.cxx unusedvariablecheck.cxx
|
||||
|
||||
# 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.
|
||||
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 ==
|
||||
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
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
|
||||
|
||||
/**
|
||||
|
||||
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: */
|
||||
|
Reference in New Issue
Block a user