1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include "sallogareas.hxx"
14 #include <clang/Lex/Lexer.h>
22 This is a compile check.
24 Check area used in SAL_INFO/SAL_WARN macros against the list in include/sal/log-areas.dox and
25 report if the area is not listed there. The fix is either use a proper area or add it to the list
29 SalLogAreas::SalLogAreas( const InstantiationData
& data
)
34 void SalLogAreas::run()
37 lastSalDetailLogStreamMacro
= SourceLocation();
38 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
41 bool SalLogAreas::VisitFunctionDecl( const FunctionDecl
* function
)
43 inFunction
= function
;
47 bool SalLogAreas::VisitCallExpr( const CallExpr
* call
)
49 if( ignoreLocation( call
))
51 if( const FunctionDecl
* func
= call
->getDirectCallee())
53 // Optimize, getQualifiedNameAsString() is reportedly expensive.
54 if( func
->getNumParams() == 4 && func
->getIdentifier() != NULL
55 && ( func
->getName() == "sal_detail_log" || func
->getName() == "log" ))
57 string qualifiedName
= func
->getQualifiedNameAsString();
58 if( qualifiedName
== "sal_detail_log" || qualifiedName
== "sal::detail::log" )
60 // The SAL_DETAIL_LOG_STREAM macro expands to two calls to sal::detail::log(),
61 // so do not warn repeatedly about the same macro (the area->getLocStart() of all the calls
62 // from the same macro should be the same).
63 SourceLocation expansionLocation
= compiler
.getSourceManager().getExpansionLoc( call
->getLocStart());
64 if( expansionLocation
== lastSalDetailLogStreamMacro
)
66 lastSalDetailLogStreamMacro
= expansionLocation
;
67 if( const StringLiteral
* area
= dyn_cast
< StringLiteral
>( call
->getArg( 1 )->IgnoreParenImpCasts()))
69 if( area
->getKind() == StringLiteral::Ascii
)
70 checkArea( area
->getBytes(), area
->getExprLoc());
72 report( DiagnosticsEngine::Warning
, "unsupported string literal kind (plugin needs fixing?)",
76 if( inFunction
->getQualifiedNameAsString() == "sal::detail::log" )
77 return true; // This function only forwards to sal_detail_log, so ok.
78 if( call
->getArg( 1 )->isNullPointerConstant( compiler
.getASTContext(),
79 Expr::NPC_ValueDependentIsNotNull
) != Expr::NPCK_NotNull
)
80 { // If the area argument is a null pointer, that is allowed only for SAL_DEBUG.
81 const SourceManager
& source
= compiler
.getSourceManager();
82 for( SourceLocation loc
= call
->getLocStart();
84 loc
= source
.getImmediateExpansionRange( loc
).first
)
86 StringRef inMacro
= Lexer::getImmediateMacroName( loc
, source
, compiler
.getLangOpts());
87 if( inMacro
== "SAL_DEBUG" )
90 report( DiagnosticsEngine::Warning
, "missing log area",
91 call
->getArg( 1 )->IgnoreParenImpCasts()->getLocStart());
94 report( DiagnosticsEngine::Warning
, "cannot analyse log area argument (plugin needs fixing?)",
102 void SalLogAreas::checkArea( StringRef area
, SourceLocation location
)
104 if( logAreas
.empty())
106 if( !logAreas
.count( area
))
108 report( DiagnosticsEngine::Warning
, "unknown log area '%0' (check or extend include/sal/log-areas.dox)",
113 void SalLogAreas::readLogAreas()
115 ifstream
is( SRCDIR
"/include/sal/log-areas.dox" );
120 size_t pos
= line
.find( "@li @c " );
121 if( pos
!= string::npos
)
123 pos
+= strlen( "@li @c " );
124 size_t end
= line
.find( ' ', pos
);
125 if( end
== string::npos
)
126 logAreas
.insert( line
.substr( pos
));
127 else if( pos
!= end
)
128 logAreas
.insert( line
.substr( pos
, end
- pos
));
131 // If you get this error message, you possibly have too old icecream (ICECC_EXTRAFILES is needed).
132 if( logAreas
.empty())
133 report( DiagnosticsEngine::Warning
, "error reading log areas" );
136 static Plugin::Registration
< SalLogAreas
> X( "sallogareas" );
140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */