update credits
[LibreOffice.git] / compilerplugins / clang / sallogareas.cxx
blob26b22a257c8cd2bbec608a8a3d5323bc5d04596d
1 /*
2 * This file is part of the LibreOffice project.
4 * Based on LLVM/Clang.
6 * This file is distributed under the University of Illinois Open Source
7 * License. See LICENSE.TXT for details.
9 */
11 #include "sallogareas.hxx"
13 #include <clang/Lex/Lexer.h>
15 #include <fstream>
17 namespace loplugin
21 This is a compile check.
23 Check area used in SAL_INFO/SAL_WARN macros against the list in include/sal/log-areas.dox and
24 report if the area is not listed there. The fix is either use a proper area or add it to the list
25 if appropriate.
28 SalLogAreas::SalLogAreas( CompilerInstance& compiler )
29 : Plugin( compiler )
33 void SalLogAreas::run()
35 inFunction = NULL;
36 lastSalDetailLogStreamMacro = SourceLocation();
37 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
40 bool SalLogAreas::VisitFunctionDecl( const FunctionDecl* function )
42 inFunction = function;
43 return true;
46 bool SalLogAreas::VisitCallExpr( const CallExpr* call )
48 if( ignoreLocation( call ))
49 return true;
50 if( const FunctionDecl* func = call->getDirectCallee())
52 // Optimize, getQualifiedNameAsString() is reportedly expensive.
53 if( func->getNumParams() == 4 && func->getIdentifier() != NULL
54 && ( func->getName() == "sal_detail_log" || func->getName() == "log" ))
56 string qualifiedName = func->getQualifiedNameAsString();
57 if( qualifiedName == "sal_detail_log" || qualifiedName == "sal::detail::log" )
59 // The SAL_DETAIL_LOG_STREAM macro expands to two calls to sal::detail::log(),
60 // so do not warn repeatedly about the same macro (the area->getLocStart() of all the calls
61 // from the same macro should be the same).
62 SourceLocation expansionLocation = compiler.getSourceManager().getExpansionLoc( call->getLocStart());
63 if( expansionLocation == lastSalDetailLogStreamMacro )
64 return true;
65 lastSalDetailLogStreamMacro = expansionLocation;
66 if( const StringLiteral* area = dyn_cast< StringLiteral >( call->getArg( 1 )->IgnoreParenImpCasts()))
68 if( area->getKind() == StringLiteral::Ascii )
69 checkArea( area->getBytes(), area->getExprLoc());
70 else
71 report( DiagnosticsEngine::Warning, "unsupported string literal kind (plugin needs fixing?)",
72 area->getLocStart());
73 return true;
75 if( inFunction->getQualifiedNameAsString() == "sal::detail::log" )
76 return true; // This function only forwards to sal_detail_log, so ok.
77 if( call->getArg( 1 )->isNullPointerConstant( compiler.getASTContext(),
78 Expr::NPC_ValueDependentIsNotNull ) != Expr::NPCK_NotNull )
79 { // If the area argument is a null pointer, that is allowed only for SAL_DEBUG.
80 const SourceManager& source = compiler.getSourceManager();
81 for( SourceLocation loc = call->getLocStart();
82 loc.isMacroID();
83 loc = source.getImmediateExpansionRange( loc ).first )
85 StringRef inMacro = Lexer::getImmediateMacroName( loc, source, compiler.getLangOpts());
86 if( inMacro == "SAL_DEBUG" )
87 return true; // ok
89 report( DiagnosticsEngine::Warning, "missing log area",
90 call->getArg( 1 )->IgnoreParenImpCasts()->getLocStart());
91 return true;
93 report( DiagnosticsEngine::Warning, "cannot analyse log area argument (plugin needs fixing?)",
94 call->getLocStart());
98 return true;
101 void SalLogAreas::checkArea( StringRef area, SourceLocation location )
103 if( logAreas.empty())
104 readLogAreas();
105 if( !logAreas.count( area ))
107 report( DiagnosticsEngine::Warning, "unknown log area '%0' (check or extend include/sal/log-areas.dox)",
108 location ) << area;
112 void SalLogAreas::readLogAreas()
114 ifstream is( SRCDIR "/include/sal/log-areas.dox" );
115 while( is.good())
117 string line;
118 getline( is, line );
119 size_t pos = line.find( "@li @c " );
120 if( pos != string::npos )
122 pos += strlen( "@li @c " );
123 size_t end = line.find( ' ', pos );
124 if( end == string::npos )
125 logAreas.insert( line.substr( pos ));
126 else if( pos != end )
127 logAreas.insert( line.substr( pos, end - pos ));
130 // If you get this error message, you possibly have too old icecream (ICECC_EXTRAFILES is needed).
131 if( logAreas.empty())
132 report( DiagnosticsEngine::Warning, "error reading log areas" );
135 static Plugin::Registration< SalLogAreas > X( "sallogareas" );
137 } // namespace