1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* 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 "sallogareas.hxx"
#include <clang/Basic/SourceManager.h>
#include <fstream>
namespace loplugin
{
/*
This is a compile check.
Check that areas used in SAL_LOG/SAL_WARN are listed in sal/inc/sal/log-areas.dox .
*/
SalLogAreas::SalLogAreas( ASTContext& context )
: Plugin( context )
{
}
void SalLogAreas::run()
{
inFunction = NULL;
TraverseDecl( context.getTranslationUnitDecl());
}
bool SalLogAreas::VisitFunctionDecl( FunctionDecl* function )
{
inFunction = function;
return true;
}
bool SalLogAreas::VisitCallExpr( CallExpr* call )
{
if( ignoreLocation( call ))
return true;
if( FunctionDecl* func = call->getDirectCallee())
{
// Optimize, getQualifiedNameAsString() is reportedly expensive.
if( func->getNumParams() == 4 && func->getIdentifier() != NULL
&& ( func->getName() == "sal_detail_log" || func->getName() == "log" ))
{
string qualifiedName = func->getQualifiedNameAsString();
if( qualifiedName == "sal_detail_log" || qualifiedName == "sal::detail::log" )
{
if( const StringLiteral* area = dyn_cast< StringLiteral >( call->getArg( 1 )->IgnoreParenImpCasts()))
{
if( area->getKind() == StringLiteral::Ascii )
checkArea( area->getBytes(), area->getExprLoc());
else
report( DiagnosticsEngine::Warning, "unsupported string literal kind (plugin needs fixing?) [loplugin]",
area->getLocStart());
return true;
}
if( inFunction->getQualifiedNameAsString() == "sal::detail::log" )
return true; // This function only forwards to sal_detail_log, so ok.
report( DiagnosticsEngine::Warning, "cannot analyse log area argument (plugin needs fixing?) [loplugin]",
call->getLocStart());
}
}
}
return true;
}
void SalLogAreas::checkArea( StringRef area, SourceLocation location )
{
if( logAreas.empty())
readLogAreas();
if( !logAreas.count( area ))
{
report( DiagnosticsEngine::Warning, "unknown log area '%0' (check or extend sal/inc/sal/log-areas.dox) [loplugin]",
location ) << area;
}
}
void SalLogAreas::readLogAreas()
{
#define STRINGIFY2( s ) #s
#define STRINGIFY( s ) STRINGIFY2( s )
ifstream is( STRINGIFY( SRCDIR ) "/sal/inc/sal/log-areas.dox" );
#undef STRINGIFY
#undef STRINGIFY2
while( is.good())
{
string line;
getline( is, line );
size_t pos = line.find( "@li @c " );
if( pos != string::npos )
{
pos += strlen( "@li @c " );
size_t end = line.find( ' ', pos );
if( end == string::npos )
logAreas.insert( line.substr( pos ));
else if( pos != end )
logAreas.insert( line.substr( pos, end - pos ));
}
}
// If you get this error message, you possibly have too old icecream (ICECC_EXTRAFILES is needed).
if( logAreas.empty())
report( DiagnosticsEngine::Warning, "error reading log areas [loplugin]" );
}
} // namespace
|