2008-10-26 08:55:15 +01:00
|
|
|
/*
|
|
|
|
* c++check - c/c++ syntax checking
|
|
|
|
* Copyright (C) 2007 Daniel Marjamäki
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2007-05-24 15:08:18 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "CheckHeaders.h"
|
2007-07-17 08:15:50 +02:00
|
|
|
#include "tokenize.h"
|
2008-11-20 23:19:26 +01:00
|
|
|
#include "CommonCheck.h"
|
|
|
|
|
2008-02-18 18:11:34 +01:00
|
|
|
#include <algorithm>
|
2007-06-09 20:25:08 +02:00
|
|
|
#include <list>
|
2007-05-24 15:08:18 +02:00
|
|
|
#include <sstream>
|
2007-06-09 20:25:08 +02:00
|
|
|
#include <string>
|
2008-08-30 20:29:37 +02:00
|
|
|
#include <cstring>
|
2007-05-24 15:08:18 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// HEADERS - No implementation in a header
|
|
|
|
//---------------------------------------------------------------------------
|
2008-11-12 22:34:47 +01:00
|
|
|
|
2008-11-20 23:19:26 +01:00
|
|
|
CheckHeaders::CheckHeaders( Tokenizer *tokenizer, ErrorLogger *errorLogger )
|
2008-11-12 22:34:47 +01:00
|
|
|
{
|
|
|
|
_tokenizer = tokenizer;
|
2008-11-20 23:19:26 +01:00
|
|
|
_errorLogger = errorLogger;
|
2008-11-12 22:34:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CheckHeaders::~CheckHeaders()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2008-11-11 07:42:09 +01:00
|
|
|
void CheckHeaders::WarningHeaderWithImplementation()
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
2008-11-16 17:13:38 +01:00
|
|
|
for ( const TOKEN *tok = _tokenizer->tokens(); tok; tok = tok->next)
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
|
|
|
// Only interested in included file
|
|
|
|
if (tok->FileIndex == 0)
|
|
|
|
continue;
|
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
if (Match(tok, ") {"))
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
|
|
|
std::ostringstream ostr;
|
2008-11-20 21:54:52 +01:00
|
|
|
ostr << _tokenizer->fileLine(tok) << ": Found implementation in header";
|
2008-11-20 23:19:26 +01:00
|
|
|
_errorLogger->reportErr(ostr.str());
|
2007-06-08 20:17:32 +02:00
|
|
|
|
|
|
|
// Goto next file..
|
|
|
|
unsigned int fileindex = tok->FileIndex;
|
|
|
|
while ( tok->next && tok->FileIndex == fileindex )
|
|
|
|
tok = tok->next;
|
2007-05-24 15:08:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// HEADERS - Unneeded include
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2008-11-11 07:42:09 +01:00
|
|
|
void CheckHeaders::WarningIncludeHeader()
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
|
|
|
// Including..
|
2008-11-16 17:13:38 +01:00
|
|
|
for ( const TOKEN *includetok = _tokenizer->tokens(); includetok; includetok = includetok->next)
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
|
|
|
if (strcmp(includetok->str, "#include") != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get fileindex of included file..
|
|
|
|
unsigned int hfile = 0;
|
|
|
|
const char *includefile = includetok->next->str;
|
2008-11-13 23:39:47 +01:00
|
|
|
while (hfile < _tokenizer->getFiles()->size())
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
2008-11-13 23:39:47 +01:00
|
|
|
if ( SameFileName( _tokenizer->getFiles()->at(hfile).c_str(), includefile ) )
|
2007-05-24 15:08:18 +02:00
|
|
|
break;
|
|
|
|
hfile++;
|
|
|
|
}
|
2008-11-13 23:39:47 +01:00
|
|
|
if (hfile == _tokenizer->getFiles()->size())
|
2007-05-24 15:08:18 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// This header is needed if:
|
|
|
|
// * It contains some needed class declaration
|
|
|
|
// * It contains some needed function declaration
|
|
|
|
// * It contains some needed constant value
|
|
|
|
// * It contains some needed variable
|
|
|
|
// * It contains some needed enum
|
2007-06-09 20:25:08 +02:00
|
|
|
|
|
|
|
std::list<std::string> classlist;
|
|
|
|
std::list<std::string> namelist;
|
|
|
|
|
|
|
|
// Extract classes and names in the header..
|
2007-05-24 15:08:18 +02:00
|
|
|
int indentlevel = 0;
|
2008-11-16 17:13:38 +01:00
|
|
|
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next )
|
2007-05-24 15:08:18 +02:00
|
|
|
{
|
2007-06-09 20:25:08 +02:00
|
|
|
if ( tok1->FileIndex != hfile )
|
2007-05-24 15:08:18 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// I'm only interested in stuff that is declared at indentlevel 0
|
2008-03-23 14:38:01 +01:00
|
|
|
if (tok1->str[0] == '{')
|
|
|
|
indentlevel++;
|
|
|
|
|
|
|
|
else if (tok1->str[0] == '}')
|
|
|
|
indentlevel--;
|
2008-11-09 08:19:53 +01:00
|
|
|
|
2007-05-24 15:08:18 +02:00
|
|
|
if (indentlevel != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Class or namespace declaration..
|
2007-06-09 20:25:08 +02:00
|
|
|
// --------------------------------------
|
2008-03-28 08:18:03 +01:00
|
|
|
if (Match(tok1,"class %var% {") || Match(tok1,"class %var% :") || Match(tok1,"namespace %var% {"))
|
2008-11-09 08:19:53 +01:00
|
|
|
classlist.push_back(Tokenizer::getstr(tok1, 1));
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2007-06-09 20:25:08 +02:00
|
|
|
// Variable declaration..
|
|
|
|
// --------------------------------------
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1, "%type% %var% ;") || Match(tok1, "%type% %var% ["))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 1));
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1, "%type% * %var% ;") || Match(tok1, "%type% * %var% ["))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 2));
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1, "const %type% %var% =") || Match(tok1, "const %type% %var% ["))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 2));
|
2007-06-09 20:25:08 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1, "const %type% * %var% =") || Match(tok1, "const %type% * %var% ["))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 3));
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2007-06-04 08:31:57 +02:00
|
|
|
// enum..
|
2007-06-09 20:25:08 +02:00
|
|
|
// --------------------------------------
|
|
|
|
else if (strcmp(tok1->str, "enum") == 0)
|
|
|
|
{
|
|
|
|
tok1 = tok1->next;
|
|
|
|
while (tok1->next && tok1->str[0]!=';')
|
|
|
|
{
|
|
|
|
if ( IsName(tok1->str) )
|
|
|
|
namelist.push_back(tok1->str);
|
|
|
|
tok1 = tok1->next;
|
|
|
|
}
|
|
|
|
}
|
2008-11-09 08:19:53 +01:00
|
|
|
|
|
|
|
// function..
|
2007-06-09 20:25:08 +02:00
|
|
|
// --------------------------------------
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1,"%type% %var% ("))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 1));
|
2007-06-09 20:25:08 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1,"%type% * %var% ("))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 2));
|
2007-06-09 20:25:08 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1,"const %type% %var% ("))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 2));
|
2007-06-09 20:25:08 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
else if (Match(tok1,"const %type% * %var% ("))
|
2008-11-09 08:19:53 +01:00
|
|
|
namelist.push_back(Tokenizer::getstr(tok1, 3));
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2007-06-08 18:46:06 +02:00
|
|
|
// typedef..
|
2007-06-09 20:25:08 +02:00
|
|
|
// --------------------------------------
|
|
|
|
else if (strcmp(tok1->str,"typedef")==0)
|
2007-06-08 18:46:06 +02:00
|
|
|
{
|
2008-11-09 08:19:53 +01:00
|
|
|
if (strcmp(Tokenizer::getstr(tok1,1),"enum")==0)
|
2007-06-09 20:25:08 +02:00
|
|
|
continue;
|
2007-06-08 18:46:06 +02:00
|
|
|
int parlevel = 0;
|
2007-06-09 20:25:08 +02:00
|
|
|
while (tok1->next)
|
2007-06-08 18:46:06 +02:00
|
|
|
{
|
|
|
|
if ( strchr("({", tok1->str[0]) )
|
|
|
|
parlevel++;
|
2007-06-09 20:25:08 +02:00
|
|
|
|
2007-06-08 19:19:31 +02:00
|
|
|
else if ( strchr(")}", tok1->str[0]) )
|
2007-06-08 18:46:06 +02:00
|
|
|
parlevel--;
|
2007-06-09 20:25:08 +02:00
|
|
|
|
|
|
|
else if (parlevel == 0)
|
2007-06-08 18:46:06 +02:00
|
|
|
{
|
2007-06-09 20:25:08 +02:00
|
|
|
if ( tok1->str[0] == ';' )
|
2007-06-08 18:46:06 +02:00
|
|
|
break;
|
2007-06-09 20:25:08 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
if ( Match(tok1, "%var% ;") )
|
2007-06-09 20:25:08 +02:00
|
|
|
namelist.push_back(tok1->str);
|
2007-06-08 18:46:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tok1 = tok1->next;
|
|
|
|
}
|
|
|
|
}
|
2007-06-09 20:25:08 +02:00
|
|
|
}
|
2007-06-08 18:46:06 +02:00
|
|
|
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2007-06-09 20:25:08 +02:00
|
|
|
// Check if the extracted names are used...
|
|
|
|
bool Needed = false;
|
|
|
|
bool NeedDeclaration = false;
|
2008-11-16 17:13:38 +01:00
|
|
|
for ( const TOKEN *tok1 = _tokenizer->tokens(); tok1; tok1 = tok1->next)
|
2007-06-09 20:25:08 +02:00
|
|
|
{
|
|
|
|
if (tok1->FileIndex != includetok->FileIndex)
|
2007-06-04 08:31:57 +02:00
|
|
|
continue;
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2008-03-28 08:18:03 +01:00
|
|
|
if ( Match(tok1, ": %var% {") || Match(tok1, ": %type% %var% {") )
|
2007-06-04 08:31:57 +02:00
|
|
|
{
|
2008-11-09 08:19:53 +01:00
|
|
|
std::string classname = Tokenizer::getstr(tok1, (strcmp(Tokenizer::getstr(tok1,2),"{")) ? 2 : 1);
|
2007-06-09 20:25:08 +02:00
|
|
|
if (std::find(classlist.begin(),classlist.end(),classname)!=classlist.end())
|
2007-06-04 08:31:57 +02:00
|
|
|
{
|
|
|
|
Needed = true;
|
2007-05-24 15:08:18 +02:00
|
|
|
break;
|
2007-06-04 08:31:57 +02:00
|
|
|
}
|
2007-05-24 15:08:18 +02:00
|
|
|
}
|
|
|
|
|
2007-06-09 20:25:08 +02:00
|
|
|
if ( ! IsName(tok1->str) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (std::find(namelist.begin(),namelist.end(),tok1->str ) != namelist.end())
|
|
|
|
{
|
|
|
|
Needed = true;
|
2007-06-04 08:31:57 +02:00
|
|
|
break;
|
2007-06-09 20:25:08 +02:00
|
|
|
}
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2007-06-09 20:25:08 +02:00
|
|
|
if ( ! NeedDeclaration )
|
2007-07-17 08:15:50 +02:00
|
|
|
NeedDeclaration = (std::find(classlist.begin(),classlist.end(),tok1->str ) != classlist.end());
|
2007-06-09 20:25:08 +02:00
|
|
|
}
|
2007-05-24 15:08:18 +02:00
|
|
|
|
2008-11-09 08:19:53 +01:00
|
|
|
|
2007-05-24 15:08:18 +02:00
|
|
|
// Not a header file?
|
|
|
|
if (includetok->FileIndex == 0)
|
|
|
|
Needed |= NeedDeclaration;
|
|
|
|
|
|
|
|
// Not needed!
|
|
|
|
if (!Needed)
|
|
|
|
{
|
|
|
|
std::ostringstream ostr;
|
2008-11-20 21:54:52 +01:00
|
|
|
ostr << _tokenizer->fileLine(includetok) << ": The included header '" << includefile << "' is not needed";
|
2007-05-24 15:08:18 +02:00
|
|
|
if (NeedDeclaration)
|
2007-06-08 20:56:11 +02:00
|
|
|
ostr << " (but a forward declaration is needed)";
|
2008-11-20 23:19:26 +01:00
|
|
|
_errorLogger->reportErr(ostr.str());
|
2007-05-24 15:08:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|