2008-12-18 22:28:57 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2008-12-18 22:28:57 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2008-12-18 22:28:57 +01:00
*/
# include "cppcheck.h"
# include "preprocessor.h" // preprocessor.
# include "tokenize.h" // <- Tokenizer
# include "filelister.h"
2009-03-19 19:24:13 +01:00
# include "check.h"
2008-12-18 22:28:57 +01:00
# include <algorithm>
2009-02-05 21:17:01 +01:00
# include <iostream>
2008-12-18 22:28:57 +01:00
# include <sstream>
# include <cstring>
# include <fstream>
2009-04-27 21:29:03 +02:00
# include <stdexcept>
2008-12-18 22:28:57 +01:00
2009-07-30 12:31:47 +02:00
# ifdef __GNUC__
# include <ctime> // clock_t
2009-10-13 11:21:41 +02:00
# define TIMER_START() clock_t c1 = clock();
# define TIMER_END(str) if(_settings._showtime){clock_t c2 = clock(); std::cout << str << ": " << ((c2 - c1) / 1000) << std::endl;}
# else
# include <ctime>
2009-10-14 19:17:20 +02:00
# define TIMER_START() std::time_t t1; std::time(&t1);
# define TIMER_END(str) if(_settings._showtime){std::time_t t2; std::time(&t2); std::cout << str << ": " << (t2 - t1) << std::endl;}
2009-07-30 12:31:47 +02:00
# endif
2008-12-18 22:28:57 +01:00
//---------------------------------------------------------------------------
2009-01-05 16:49:57 +01:00
CppCheck : : CppCheck ( ErrorLogger & errorLogger )
2009-10-27 10:10:59 +01:00
: _errorLogger ( errorLogger )
2008-12-18 22:28:57 +01:00
{
2009-12-31 13:34:43 +01:00
exitcode = 0 ;
2008-12-18 22:28:57 +01:00
}
CppCheck : : ~ CppCheck ( )
{
}
2009-01-05 16:49:57 +01:00
void CppCheck : : settings ( const Settings & settings )
2008-12-18 22:28:57 +01:00
{
_settings = settings ;
}
2009-01-05 16:49:57 +01:00
void CppCheck : : addFile ( const std : : string & path )
2008-12-18 22:28:57 +01:00
{
2009-07-05 22:16:43 +02:00
FileLister : : recursiveAddFiles ( _filenames , path . c_str ( ) , true ) ;
2008-12-18 22:28:57 +01:00
}
2009-01-05 16:49:57 +01:00
void CppCheck : : addFile ( const std : : string & path , const std : : string & content )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
_filenames . push_back ( path ) ;
2008-12-18 22:28:57 +01:00
_fileContents [ path ] = content ;
}
2009-02-27 20:39:50 +01:00
void CppCheck : : clearFiles ( )
{
_filenames . clear ( ) ;
_fileContents . clear ( ) ;
}
2009-10-25 21:06:58 +01:00
const char * CppCheck : : version ( )
2009-10-17 11:34:17 +02:00
{
2010-03-07 16:25:37 +01:00
return " 1.41 " ;
2009-10-17 11:34:17 +02:00
}
2009-06-12 15:20:08 +02:00
2010-01-27 21:43:01 +01:00
static void AddFilesToList ( const std : : string & FileList , std : : vector < std : : string > & PathNames )
{
// to keep things initially simple, if the file can't be opened, just be
// silent and move on
// ideas : we could also require this should be an xml file, with the filenames
// specified in an xml structure
// we could elaborate this then, to also include the I-paths, ...
// basically for everything that makes the command line very long
// xml is a bonus then, since we can easily extend it
// we need a good parser then -> suggestion : TinyXml
// drawback : creates a dependency
std : : ifstream Files ( FileList . c_str ( ) ) ;
if ( Files )
{
std : : string FileName ;
while ( std : : getline ( Files , FileName ) ) // next line
{
if ( ! FileName . empty ( ) )
{
PathNames . push_back ( FileName ) ;
}
}
}
}
2009-10-17 08:19:37 +02:00
void CppCheck : : parseFromArgs ( int argc , const char * const argv [ ] )
2008-12-18 22:28:57 +01:00
{
std : : vector < std : : string > pathnames ;
2009-01-25 12:05:51 +01:00
bool showHelp = false ;
2008-12-18 22:28:57 +01:00
for ( int i = 1 ; i < argc ; i + + )
{
2009-03-06 22:17:42 +01:00
if ( strcmp ( argv [ i ] , " --version " ) = = 0 )
2009-10-17 08:19:37 +02:00
{
2009-10-17 11:34:17 +02:00
reportOut ( std : : string ( " Cppcheck " ) + version ( ) ) ;
2009-10-17 08:19:37 +02:00
return ;
}
2009-03-06 22:17:42 +01:00
2008-12-18 22:28:57 +01:00
// Flag used for various purposes during debugging
2009-10-17 08:19:37 +02:00
else if ( strcmp ( argv [ i ] , " --debug " ) = = 0 )
2008-12-18 22:28:57 +01:00
_settings . _debug = true ;
// Show all messages
2009-01-05 16:49:57 +01:00
else if ( strcmp ( argv [ i ] , " -a " ) = = 0 | | strcmp ( argv [ i ] , " --all " ) = = 0 )
2009-11-30 22:48:58 +01:00
_settings . addEnabled ( " possibleError " ) ;
2008-12-18 22:28:57 +01:00
// Only print something when there are errors
2009-01-05 16:49:57 +01:00
else if ( strcmp ( argv [ i ] , " -q " ) = = 0 | | strcmp ( argv [ i ] , " --quiet " ) = = 0 )
2008-12-18 22:28:57 +01:00
_settings . _errorsOnly = true ;
// Checking coding style
2009-01-05 16:49:57 +01:00
else if ( strcmp ( argv [ i ] , " -s " ) = = 0 | | strcmp ( argv [ i ] , " --style " ) = = 0 )
2009-11-30 22:48:58 +01:00
_settings . addEnabled ( " style " ) ;
2008-12-18 22:28:57 +01:00
2009-10-08 16:56:30 +02:00
// Filter errors
else if ( strcmp ( argv [ i ] , " --suppressions " ) = = 0 )
{
+ + i ;
if ( i > = argc )
2009-12-05 08:08:28 +01:00
throw std : : runtime_error ( " cppcheck: No file specified for the --suppressions option " ) ;
2009-10-08 16:56:30 +02:00
std : : ifstream f ( argv [ i ] ) ;
if ( ! f . is_open ( ) )
2009-12-05 08:08:28 +01:00
throw std : : runtime_error ( " cppcheck: Couldn't open the file \" " + std : : string ( argv [ i ] ) + " \" " ) ;
2009-12-28 11:23:58 +01:00
_settings . nomsg . parseFile ( f ) ;
}
// Filter errors
else if ( strcmp ( argv [ i ] , " --exitcode-suppressions " ) = = 0 )
{
+ + i ;
if ( i > = argc )
throw std : : runtime_error ( " cppcheck: No file specified for the --exitcode-suppressions option " ) ;
std : : ifstream f ( argv [ i ] ) ;
if ( ! f . is_open ( ) )
throw std : : runtime_error ( " cppcheck: Couldn't open the file \" " + std : : string ( argv [ i ] ) + " \" " ) ;
_settings . nofail . parseFile ( f ) ;
2009-10-08 16:56:30 +02:00
}
2009-12-06 19:38:53 +01:00
// Enables inline suppressions.
else if ( strcmp ( argv [ i ] , " --inline-suppr " ) = = 0 )
_settings . _inlineSuppressions = true ;
2008-12-18 22:28:57 +01:00
// Verbose error messages (configuration info)
2009-01-05 16:49:57 +01:00
else if ( strcmp ( argv [ i ] , " -v " ) = = 0 | | strcmp ( argv [ i ] , " --verbose " ) = = 0 )
2008-12-18 22:28:57 +01:00
_settings . _verbose = true ;
2008-12-27 08:52:07 +01:00
// Force checking of files that have "too many" configurations
2009-01-05 16:49:57 +01:00
else if ( strcmp ( argv [ i ] , " -f " ) = = 0 | | strcmp ( argv [ i ] , " --force " ) = = 0 )
2008-12-27 08:52:07 +01:00
_settings . _force = true ;
2009-01-28 18:12:43 +01:00
// Write results in results.xml
2009-02-01 19:00:47 +01:00
else if ( strcmp ( argv [ i ] , " --xml " ) = = 0 )
_settings . _xml = true ;
2009-01-28 18:12:43 +01:00
2009-01-28 18:26:19 +01:00
// Check if there are unused functions
else if ( strcmp ( argv [ i ] , " --unused-functions " ) = = 0 )
2009-11-30 22:48:58 +01:00
_settings . addEnabled ( " unusedFunctions " ) ;
2009-01-28 18:26:19 +01:00
2009-09-08 19:49:05 +02:00
// Append userdefined code to checked source code
else if ( strncmp ( argv [ i ] , " --append= " , 9 ) = = 0 )
_settings . append ( 9 + argv [ i ] ) ;
2009-07-27 14:41:34 +02:00
// show timing information..
else if ( strcmp ( argv [ i ] , " --showtime " ) = = 0 )
_settings . _showtime = true ;
2009-01-22 21:26:04 +01:00
// Print help
else if ( strcmp ( argv [ i ] , " -h " ) = = 0 | | strcmp ( argv [ i ] , " --help " ) = = 0 )
{
pathnames . clear ( ) ;
_filenames . clear ( ) ;
2009-01-25 12:05:51 +01:00
showHelp = true ;
2009-01-22 21:26:04 +01:00
break ;
}
2009-03-06 01:03:31 +01:00
2009-11-15 15:24:33 +01:00
else if ( strncmp ( argv [ i ] , " --enable= " , 9 ) = = 0 )
{
2009-12-04 19:35:58 +01:00
_settings . addEnabled ( argv [ i ] + 9 ) ;
2009-11-15 15:24:33 +01:00
}
2009-03-06 01:03:31 +01:00
// --error-exitcode=1
else if ( strncmp ( argv [ i ] , " --error-exitcode= " , 17 ) = = 0 )
{
std : : string temp = argv [ i ] ;
temp = temp . substr ( 17 ) ;
std : : istringstream iss ( temp ) ;
if ( ! ( iss > > _settings . _exitCode ) )
{
_settings . _exitCode = 0 ;
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: Argument must be an integer. Try something like '--error-exitcode=1' " ) ;
2009-03-06 01:03:31 +01:00
}
}
2009-01-22 20:59:50 +01:00
// Include paths
else if ( strcmp ( argv [ i ] , " -I " ) = = 0 | | strncmp ( argv [ i ] , " -I " , 2 ) = = 0 )
{
std : : string path ;
// "-I path/"
if ( strcmp ( argv [ i ] , " -I " ) = = 0 )
{
+ + i ;
if ( i > = argc )
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: argument to '-I' is missing " ) ;
2009-01-22 20:59:50 +01:00
path = argv [ i ] ;
}
// "-Ipath/"
else
{
path = argv [ i ] ;
path = path . substr ( 2 ) ;
}
// If path doesn't end with / or \, add it
if ( path [ path . length ( ) - 1 ] ! = ' / ' & & path [ path . length ( ) - 1 ] ! = ' \\ ' )
path + = ' / ' ;
2009-07-04 00:23:37 +02:00
_settings . _includePaths . push_back ( path ) ;
2009-01-22 20:59:50 +01:00
}
2010-01-27 21:43:01 +01:00
// file list specified
else if ( strncmp ( argv [ i ] , " --file-list= " , 12 ) = = 0 )
{
// open this file and read every input file (1 file name per line)
AddFilesToList ( 12 + argv [ i ] , pathnames ) ;
}
2009-09-05 21:01:49 +02:00
// Output formatter
else if ( strcmp ( argv [ i ] , " --template " ) = = 0 )
{
// "--template path/"
2009-09-27 16:53:09 +02:00
+ + i ;
if ( i > = argc )
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: argument to '--template' is missing " ) ;
2009-09-05 21:01:49 +02:00
2009-09-27 16:53:09 +02:00
_settings . _outputFormat = argv [ i ] ;
2009-09-28 21:48:27 +02:00
if ( _settings . _outputFormat = = " gcc " )
_settings . _outputFormat = " {file}:{line}: {severity}: {message} " ;
else if ( _settings . _outputFormat = = " vs " )
_settings . _outputFormat = " {file}({line}): {severity}: {message} " ;
2009-09-05 21:01:49 +02:00
}
2010-02-26 12:21:27 +01:00
// Checking threads
2009-02-22 19:38:10 +01:00
else if ( strcmp ( argv [ i ] , " -j " ) = = 0 | |
strncmp ( argv [ i ] , " -j " , 2 ) = = 0 )
2009-02-20 20:40:42 +01:00
{
std : : string numberString ;
2009-02-22 19:38:10 +01:00
// "-j 3"
if ( strcmp ( argv [ i ] , " -j " ) = = 0 )
2009-02-20 20:40:42 +01:00
{
+ + i ;
if ( i > = argc )
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: argument to '-j' is missing " ) ;
2009-02-20 20:40:42 +01:00
numberString = argv [ i ] ;
}
2009-02-22 19:38:10 +01:00
// "-j3"
else if ( strncmp ( argv [ i ] , " -j " , 2 ) = = 0 )
2009-02-20 20:40:42 +01:00
{
numberString = argv [ i ] ;
numberString = numberString . substr ( 2 ) ;
}
std : : istringstream iss ( numberString ) ;
2009-02-22 19:38:10 +01:00
if ( ! ( iss > > _settings . _jobs ) )
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: argument to '-j' is not a number " ) ;
2009-02-20 20:40:42 +01:00
2009-02-22 19:38:10 +01:00
if ( _settings . _jobs > 1000 )
2009-02-20 20:40:42 +01:00
{
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: argument for '-j' is allowed to be 1000 at max " ) ;
2009-02-20 20:40:42 +01:00
}
}
2009-03-06 17:38:47 +01:00
// auto deallocated classes..
2009-03-06 18:13:41 +01:00
else if ( strcmp ( argv [ i ] , " --auto-dealloc " ) = = 0 )
2009-03-06 17:38:47 +01:00
{
+ + i ;
2009-03-06 18:13:41 +01:00
if ( i > = argc | | ! strstr ( argv [ i ] , " .lst " ) )
2009-12-05 08:08:28 +01:00
throw std : : runtime_error ( " cppcheck: No .lst file specified for the --auto-dealloc option " ) ;
2009-03-06 17:38:47 +01:00
std : : ifstream f ( argv [ i ] ) ;
if ( ! f . is_open ( ) )
2009-12-05 08:08:28 +01:00
throw std : : runtime_error ( " cppcheck: couldn't open the file \" " + std : : string ( argv [ i + 1 ] ) + " \" " ) ;
2009-03-06 17:38:47 +01:00
_settings . autoDealloc ( f ) ;
}
2009-06-05 18:34:55 +02:00
// print all possible error messages..
else if ( strcmp ( argv [ i ] , " --errorlist " ) = = 0 )
{
// call all "getErrorMessages" in all registered Check classes
2009-08-04 21:36:55 +02:00
std : : cout < < ErrorLogger : : ErrorMessage : : getXMLHeader ( ) ;
2009-06-05 18:34:55 +02:00
for ( std : : list < Check * > : : iterator it = Check : : instances ( ) . begin ( ) ; it ! = Check : : instances ( ) . end ( ) ; + + it )
{
( * it ) - > getErrorMessages ( ) ;
}
2009-10-17 23:11:48 +02:00
Tokenizer tokenizer ( & _settings , 0 ) ;
tokenizer . getErrorMessages ( ) ;
2009-08-04 21:36:55 +02:00
std : : cout < < ErrorLogger : : ErrorMessage : : getXMLFooter ( ) < < std : : endl ;
2010-02-06 19:47:08 +01:00
return ;
2009-06-05 18:34:55 +02:00
}
2009-06-12 15:20:08 +02:00
// documentation..
else if ( strcmp ( argv [ i ] , " --doc " ) = = 0 )
{
std : : ostringstream doc ;
// Get documentation..
for ( std : : list < Check * > : : iterator it = Check : : instances ( ) . begin ( ) ; it ! = Check : : instances ( ) . end ( ) ; + + it )
{
doc < < " === " < < ( * it ) - > name ( ) < < " === \n "
2009-06-12 17:24:43 +02:00
< < ( * it ) - > classInfo ( ) < < " \n \n " ;
2009-06-12 15:20:08 +02:00
}
doc < < " === " < < " Unused functions " < < " === \n "
2009-06-12 17:24:43 +02:00
< < " Check for functions that are never called \n " ;
2009-06-12 15:20:08 +02:00
std : : string doc2 ( doc . str ( ) ) ;
while ( doc2 . find ( " \n \n \n " ) ! = std : : string : : npos )
doc2 . erase ( doc2 . find ( " \n \n \n " ) , 1 ) ;
std : : cout < < doc2 ;
2009-10-17 08:19:37 +02:00
return ;
2009-06-12 15:20:08 +02:00
}
2009-01-22 21:26:04 +01:00
else if ( strncmp ( argv [ i ] , " - " , 1 ) = = 0 | | strncmp ( argv [ i ] , " -- " , 2 ) = = 0 )
{
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: error: unrecognized command line option \" " + std : : string ( argv [ i ] ) + " \" " ) ;
2009-01-22 21:26:04 +01:00
}
2008-12-18 22:28:57 +01:00
else
2009-01-05 16:49:57 +01:00
pathnames . push_back ( argv [ i ] ) ;
2008-12-18 22:28:57 +01:00
}
2009-11-30 22:48:58 +01:00
if ( _settings . isEnabled ( " unusedFunctions " ) & & _settings . _jobs > 1 )
2009-07-02 22:29:52 +02:00
{
2009-11-30 22:48:58 +01:00
reportOut ( " unusedFunctions check can't be used with -j option, so it was disabled. " ) ;
2009-07-02 22:29:52 +02:00
}
2009-12-23 12:16:02 +01:00
if ( ! pathnames . empty ( ) )
2008-12-18 22:28:57 +01:00
{
2009-07-05 22:16:43 +02:00
// Execute recursiveAddFiles() to each given file parameter
2008-12-18 22:28:57 +01:00
std : : vector < std : : string > : : const_iterator iter ;
2009-12-25 15:19:36 +01:00
for ( iter = pathnames . begin ( ) ; iter ! = pathnames . end ( ) ; + + iter )
2009-07-05 22:16:43 +02:00
FileLister : : recursiveAddFiles ( _filenames , iter - > c_str ( ) , true ) ;
2008-12-18 22:28:57 +01:00
}
2009-01-25 12:05:51 +01:00
if ( argc < = 1 | | showHelp )
2008-12-18 22:28:57 +01:00
{
std : : ostringstream oss ;
2009-03-06 22:17:42 +01:00
oss < < " Cppcheck - A tool for static C/C++ code analysis \n "
2009-01-05 16:49:57 +01:00
" \n "
" Syntax: \n "
2009-11-15 15:36:57 +01:00
" cppcheck [--all] [--append=file] [--auto-dealloc file.lst] [--enable] \n "
2009-12-28 11:23:58 +01:00
" [--error-exitcode=[n]] [--exitcode-suppressions file] [--force] \n "
" [--help] [-Idir] [-j [jobs]] [--quiet] [--style] \n "
2010-01-27 21:43:01 +01:00
" [--suppressions file.txt] [--inline-suppr] [--file-list=file.txt] \n "
" [--verbose] [--version] [--xml] [file or path1] [file or path] .. \n "
2009-01-05 16:49:57 +01:00
" \n "
2009-01-16 23:42:08 +01:00
" If path is given instead of filename, *.cpp, *.cxx, *.cc, *.c++ and *.c files \n "
" are checked recursively from given directory. \n \n "
2009-01-05 16:49:57 +01:00
" Options: \n "
2009-11-29 17:59:12 +01:00
" -a, --all deprecated, use --enable=possibleError \n "
2009-09-08 19:49:05 +02:00
" --append=file This allows you to provide information about \n "
" functions by providing an implementation for these. \n "
2009-03-07 08:56:12 +01:00
" --auto-dealloc file Suppress warnings about classes that have automatic \n "
" deallocation. \n "
" The classnames must be provided in plain text - one \n "
" classname / line - in a .lst file. \n "
" This option can be used several times, allowing you to \n "
" specify several .lst files. \n "
2009-11-15 15:36:57 +01:00
" --enable=id Enable specific checks. The available ids are: \n "
2009-12-05 20:08:52 +01:00
" * all - enable all checks \n "
2009-11-15 15:36:57 +01:00
" * exceptNew - exception safety when using new \n "
" * exceptRealloc - exception safety when reallocating \n "
2009-11-29 17:59:12 +01:00
" * possibleError - Make the checking more sensitive. \n "
" More bugs are detected, but there are also \n "
" more false positives \n "
" * style - Check coding style \n "
2009-11-15 15:36:57 +01:00
" * unusedFunctions - check for unused functions \n "
" Several ids can be given if you separate them with commas \n "
2009-03-06 01:03:31 +01:00
" --error-exitcode=[n] If errors are found, integer [n] is returned instead \n "
" of default 0. EXIT_FAILURE is returned \n "
" if arguments are not valid or if no input files are \n "
" provided. Note that your operating system can \n "
" modify this value, e.g. 256 can become 0. \n "
2009-12-28 11:23:58 +01:00
" --exitcode-suppressions file \n "
" Used when certain messages should be displayed but \n "
" should not cause a non-zero exitcode. \n "
2009-01-28 18:26:19 +01:00
" -f, --force Force checking on files that have \" too many \" \n "
" configurations \n "
" -h, --help Print this help \n "
2009-02-20 20:40:42 +01:00
" -I [dir] Give include path. Give several -I parameters to give \n "
2009-01-28 18:26:19 +01:00
" several paths. First given path is checked first. If \n "
" paths are relative to source files, this is not needed \n "
2009-03-06 22:17:42 +01:00
" -j [jobs] Start [jobs] threads to do the checking simultaneously. \n "
2009-01-28 18:26:19 +01:00
" -q, --quiet Only print error messages \n "
2009-11-29 17:59:12 +01:00
" -s, --style deprecated, use --enable=style \n "
2009-10-08 16:56:30 +02:00
" --suppressions file Suppress warnings listed in the file. Filename and line \n "
" are optional. The format of the single line in file is: \n "
" [error id]:[filename]:[line] \n "
2009-12-06 19:38:53 +01:00
" --inline-suppr Enable inline suppressions. Use them by placing one or \n "
" more comments in the form: // cppcheck-suppress memleak \n "
" on the lines before the warning to suppress. \n "
2010-01-27 21:43:01 +01:00
" --file-list=file Specify the files to check in a text file. One Filename per line. \n "
2009-09-05 21:01:49 +02:00
" --template '[text]' Format the error messages. E.g. \n "
" '{file}:{line},{severity},{id},{message}' or \n "
" '{file}({line}):({severity}) {message}' \n "
2009-09-28 21:48:27 +02:00
" Pre-defined templates: gcc, vs \n "
2009-11-30 21:45:05 +01:00
" --unused-functions deprecated, use --enable=unusedFunctions \n "
2009-01-28 18:26:19 +01:00
" -v, --verbose More detailed error reports \n "
2009-03-06 22:17:42 +01:00
" --version Print out version number \n "
2009-02-09 21:51:04 +01:00
" --xml Write results in xml to error stream. \n "
2009-01-05 16:49:57 +01:00
" \n "
" Example usage: \n "
2009-01-24 19:24:04 +01:00
" # Recursively check the current folder. Print the progress on the screen and \n "
" write errors in a file: \n "
2009-01-05 16:49:57 +01:00
" cppcheck . 2> err.txt \n "
" # Recursively check ../myproject/ and print only most fatal errors: \n "
" cppcheck --quiet ../myproject/ \n "
" # Check only files one.cpp and two.cpp and give all information there is: \n "
2009-01-22 20:59:50 +01:00
" cppcheck -v -a -s one.cpp two.cpp \n "
" # Check f.cpp and search include files from inc1/ and inc2/: \n "
" cppcheck -I inc1/ -I inc2/ f.cpp \n " ;
2009-10-17 08:19:37 +02:00
reportOut ( oss . str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2009-01-25 12:05:51 +01:00
else if ( _filenames . empty ( ) )
{
2009-10-17 08:19:37 +02:00
throw std : : runtime_error ( " cppcheck: No C or C++ source files found. " ) ;
2009-01-25 12:05:51 +01:00
}
2008-12-18 22:28:57 +01:00
}
2009-01-08 22:30:25 +01:00
unsigned int CppCheck : : check ( )
2008-12-18 22:28:57 +01:00
{
2009-12-28 11:23:58 +01:00
exitcode = 0 ;
2009-06-07 22:12:20 +02:00
_checkUnusedFunctions . setErrorLogger ( this ) ;
2009-01-05 16:49:57 +01:00
std : : sort ( _filenames . begin ( ) , _filenames . end ( ) ) ;
2008-12-18 22:28:57 +01:00
for ( unsigned int c = 0 ; c < _filenames . size ( ) ; c + + )
{
_errout . str ( " " ) ;
2010-01-18 20:23:50 +01:00
const std : : string fname = _filenames [ c ] ;
if ( _settings . terminated ( ) )
break ;
2008-12-18 22:28:57 +01:00
2009-01-19 20:00:36 +01:00
if ( _settings . _errorsOnly = = false )
2009-10-26 21:31:36 +01:00
_errorLogger . reportOut ( std : : string ( " Checking " ) + fname + std : : string ( " ... " ) ) ;
2008-12-18 22:28:57 +01:00
2009-04-27 21:29:03 +02:00
try
2008-12-18 22:28:57 +01:00
{
2009-07-25 21:10:30 +02:00
Preprocessor preprocessor ( & _settings , this ) ;
2009-04-27 21:29:03 +02:00
std : : list < std : : string > configurations ;
std : : string filedata = " " ;
2008-12-18 22:28:57 +01:00
2009-04-27 21:29:03 +02:00
if ( _fileContents . size ( ) > 0 & & _fileContents . find ( _filenames [ c ] ) ! = _fileContents . end ( ) )
2008-12-27 08:52:07 +01:00
{
2009-04-27 21:29:03 +02:00
// File content was given as a string
std : : istringstream iss ( _fileContents [ _filenames [ c ] ] ) ;
2009-07-04 00:23:37 +02:00
preprocessor . preprocess ( iss , filedata , configurations , fname , _settings . _includePaths ) ;
2008-12-27 08:52:07 +01:00
}
2009-04-27 21:29:03 +02:00
else
{
// Only file name was given, read the content from file
std : : ifstream fin ( fname . c_str ( ) ) ;
2009-10-13 11:21:41 +02:00
TIMER_START ( ) ;
2009-07-04 00:23:37 +02:00
preprocessor . preprocess ( fin , filedata , configurations , fname , _settings . _includePaths ) ;
2009-10-13 11:21:41 +02:00
TIMER_END ( " Preprocessor::preprocess " ) ;
2009-04-27 21:29:03 +02:00
}
int checkCount = 0 ;
for ( std : : list < std : : string > : : const_iterator it = configurations . begin ( ) ; it ! = configurations . end ( ) ; + + it )
{
// Check only 12 first configurations, after that bail out, unless --force
// was used.
if ( ! _settings . _force & & checkCount > 11 )
{
if ( _settings . _errorsOnly = = false )
2009-10-26 21:31:36 +01:00
_errorLogger . reportOut ( std : : string ( " Bailing out from checking " ) + fname + " : Too many configurations. Recheck this file with --force if you want to check them all. " ) ;
2009-04-27 21:29:03 +02:00
break ;
}
2008-12-27 08:52:07 +01:00
2009-04-27 21:29:03 +02:00
cfg = * it ;
2009-10-13 11:21:41 +02:00
TIMER_START ( ) ;
2009-10-26 21:31:36 +01:00
const std : : string codeWithoutCfg = Preprocessor : : getcode ( filedata , * it , fname , & _errorLogger ) ;
2009-10-13 11:21:41 +02:00
TIMER_END ( " Preprocessor::getcode " ) ;
2008-12-26 23:52:27 +01:00
2009-04-27 21:29:03 +02:00
// If only errors are printed, print filename after the check
if ( _settings . _errorsOnly = = false & & it ! = configurations . begin ( ) )
2009-10-26 21:31:36 +01:00
_errorLogger . reportOut ( std : : string ( " Checking " ) + fname + " : " + cfg + std : : string ( " ... " ) ) ;
2008-12-26 23:52:27 +01:00
2009-09-08 19:49:05 +02:00
checkFile ( codeWithoutCfg + _settings . append ( ) , _filenames [ c ] . c_str ( ) ) ;
2009-04-27 21:29:03 +02:00
+ + checkCount ;
}
}
catch ( std : : runtime_error & e )
{
// Exception was thrown when checking this file..
2009-10-26 21:31:36 +01:00
_errorLogger . reportOut ( " Bailing out from checking " + fname + " : " + e . what ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2009-10-26 21:31:36 +01:00
_errorLogger . reportStatus ( c + 1 , ( unsigned int ) _filenames . size ( ) ) ;
2008-12-18 22:28:57 +01:00
}
// This generates false positives - especially for libraries
_settings . _verbose = false ;
2009-11-30 22:48:58 +01:00
if ( _settings . isEnabled ( " unusedFunctions " ) & & _settings . _jobs = = 1 )
2008-12-18 22:28:57 +01:00
{
_errout . str ( " " ) ;
2009-01-05 16:49:57 +01:00
if ( _settings . _errorsOnly = = false )
2009-10-26 21:31:36 +01:00
_errorLogger . reportOut ( " Checking usage of global functions.. " ) ;
2008-12-18 22:28:57 +01:00
2009-06-07 22:12:20 +02:00
_checkUnusedFunctions . check ( ) ;
2008-12-18 22:28:57 +01:00
}
_errorList . clear ( ) ;
2009-12-28 11:23:58 +01:00
return exitcode ;
2008-12-18 22:28:57 +01:00
}
//---------------------------------------------------------------------------
// CppCheck - A function that checks a specified file
//---------------------------------------------------------------------------
void CppCheck : : checkFile ( const std : : string & code , const char FileName [ ] )
{
2010-01-18 20:23:50 +01:00
if ( _settings . terminated ( ) )
return ;
2009-07-13 19:11:31 +02:00
Tokenizer _tokenizer ( & _settings , this ) ;
2008-12-18 22:28:57 +01:00
// Tokenize the file
{
2009-01-05 16:49:57 +01:00
std : : istringstream istr ( code ) ;
2009-10-13 11:21:41 +02:00
TIMER_START ( ) ;
2010-01-23 22:18:11 +01:00
if ( ! _tokenizer . tokenize ( istr , FileName , cfg ) )
2009-05-07 22:17:29 +02:00
{
// File had syntax errors, abort
return ;
}
2009-10-13 11:21:41 +02:00
TIMER_END ( " Tokenizer::tokenize " ) ;
2008-12-18 22:28:57 +01:00
}
2009-10-13 11:21:41 +02:00
{
TIMER_START ( ) ;
_tokenizer . fillFunctionList ( ) ;
TIMER_END ( " Tokenizer::fillFunctionList " ) ;
}
2008-12-18 22:28:57 +01:00
2009-03-21 07:53:23 +01:00
// call all "runChecks" in all registered Check classes
for ( std : : list < Check * > : : iterator it = Check : : instances ( ) . begin ( ) ; it ! = Check : : instances ( ) . end ( ) ; + + it )
{
2010-01-18 20:23:50 +01:00
if ( _settings . terminated ( ) )
return ;
2009-10-13 11:21:41 +02:00
TIMER_START ( ) ;
2009-03-21 07:53:23 +01:00
( * it ) - > runChecks ( & _tokenizer , & _settings , this ) ;
2009-10-13 11:21:41 +02:00
TIMER_END ( ( * it ) - > name ( ) < < " ::runChecks " ) ;
2009-03-21 07:53:23 +01:00
}
2008-12-18 22:28:57 +01:00
2009-07-27 14:41:34 +02:00
{
2009-10-13 11:21:41 +02:00
TIMER_START ( ) ;
2009-11-10 22:10:56 +01:00
bool result = _tokenizer . simplifyTokenList ( ) ;
2009-10-13 11:21:41 +02:00
TIMER_END ( " Tokenizer::simplifyTokenList " ) ;
2009-11-10 22:10:56 +01:00
if ( ! result )
return ;
2009-07-27 14:41:34 +02:00
}
2008-12-18 22:28:57 +01:00
2010-01-16 13:56:57 +01:00
{
TIMER_START ( ) ;
_tokenizer . fillFunctionList ( ) ;
TIMER_END ( " Tokenizer::fillFunctionList " ) ;
}
2009-11-15 15:24:33 +01:00
2009-11-30 22:48:58 +01:00
if ( _settings . isEnabled ( " unusedFunctions " ) & & _settings . _jobs = = 1 )
2009-06-07 22:12:20 +02:00
_checkUnusedFunctions . parseTokens ( _tokenizer ) ;
2008-12-18 22:28:57 +01:00
2009-03-21 07:53:23 +01:00
// call all "runSimplifiedChecks" in all registered Check classes
2009-03-19 19:24:13 +01:00
for ( std : : list < Check * > : : iterator it = Check : : instances ( ) . begin ( ) ; it ! = Check : : instances ( ) . end ( ) ; + + it )
{
2010-01-18 20:23:50 +01:00
if ( _settings . terminated ( ) )
return ;
2009-10-13 11:21:41 +02:00
TIMER_START ( ) ;
2009-03-21 07:53:23 +01:00
( * it ) - > runSimplifiedChecks ( & _tokenizer , & _settings , this ) ;
2009-10-13 11:21:41 +02:00
TIMER_END ( ( * it ) - > name ( ) < < " ::runSimplifiedChecks " ) ;
2009-03-19 19:24:13 +01:00
}
2008-12-18 22:28:57 +01:00
}
2009-02-09 21:51:04 +01:00
Settings CppCheck : : settings ( ) const
{
return _settings ;
}
2008-12-18 22:28:57 +01:00
//---------------------------------------------------------------------------
2009-02-10 22:51:52 +01:00
void CppCheck : : reportErr ( const ErrorLogger : : ErrorMessage & msg )
2008-12-18 22:28:57 +01:00
{
2009-07-10 22:38:26 +02:00
std : : string errmsg = msg . toText ( ) ;
2009-02-09 21:51:04 +01:00
2009-02-07 16:37:01 +01:00
// Alert only about unique errors
if ( std : : find ( _errorList . begin ( ) , _errorList . end ( ) , errmsg ) ! = _errorList . end ( ) )
return ;
2008-12-18 22:28:57 +01:00
2009-10-08 16:56:30 +02:00
std : : string file ;
unsigned int line ( 0 ) ;
if ( ! msg . _callStack . empty ( ) )
{
file = msg . _callStack . back ( ) . getfile ( ) ;
line = msg . _callStack . back ( ) . line ;
}
2009-12-28 11:23:58 +01:00
if ( _settings . nomsg . isSuppressed ( msg . _id , file , line ) )
2009-10-08 16:56:30 +02:00
return ;
2009-12-28 11:23:58 +01:00
if ( ! _settings . nofail . isSuppressed ( msg . _id , file , line ) )
exitcode = 1 ;
2009-02-07 16:37:01 +01:00
_errorList . push_back ( errmsg ) ;
2009-01-05 16:49:57 +01:00
std : : string errmsg2 ( errmsg ) ;
if ( _settings . _verbose )
2008-12-18 22:28:57 +01:00
{
errmsg2 + = " \n Defines= \' " + cfg + " \' \n " ;
}
2009-10-26 21:31:36 +01:00
_errorLogger . reportErr ( msg ) ;
2008-12-18 22:28:57 +01:00
_errout < < errmsg2 < < std : : endl ;
}
2009-07-25 21:10:30 +02:00
void CppCheck : : reportOut ( const std : : string & outmsg )
2008-12-18 22:28:57 +01:00
{
2009-10-26 21:31:36 +01:00
_errorLogger . reportOut ( outmsg ) ;
2008-12-18 22:28:57 +01:00
}
2009-02-19 23:21:18 +01:00
const std : : vector < std : : string > & CppCheck : : filenames ( ) const
{
return _filenames ;
}
void CppCheck : : reportStatus ( unsigned int /*index*/ , unsigned int /*max*/ )
{
}