113 lines
4.1 KiB
C++
113 lines
4.1 KiB
C++
|
/*
|
||
|
* 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
|