Initial work for class and member function/variable list in tokenizer.

This commit is contained in:
Reijo Tomperi 2009-08-12 23:50:03 +03:00
parent bcab694a74
commit 4f8a06ed0d
5 changed files with 207 additions and 0 deletions

View File

@ -87,6 +87,7 @@
<Unit filename="src/checkstl.h" /> <Unit filename="src/checkstl.h" />
<Unit filename="src/checkunusedfunctions.cpp" /> <Unit filename="src/checkunusedfunctions.cpp" />
<Unit filename="src/checkunusedfunctions.h" /> <Unit filename="src/checkunusedfunctions.h" />
<Unit filename="src/classinfo.h" />
<Unit filename="src/cppcheck.cpp" /> <Unit filename="src/cppcheck.cpp" />
<Unit filename="src/cppcheck.h" /> <Unit filename="src/cppcheck.h" />
<Unit filename="src/cppcheckexecutor.cpp" /> <Unit filename="src/cppcheckexecutor.cpp" />

96
src/classinfo.h Normal file
View File

@ -0,0 +1,96 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team.
*
* 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/
*/
//---------------------------------------------------------------------------
#ifndef classInfoH
#define classInfoH
//---------------------------------------------------------------------------
#include <string>
#include <vector>
#include "token.h"
/// @addtogroup Core
/// @{
/** @brief Holds information about a single class in checked source code. Contains member function and member variable lists. */
class ClassInfo
{
public:
enum MemberType {PRIVATE, PROTECTED, PUBLIC};
/**
* Base class for both member functions and member variables.
* Contains variable name, token where name was declared and type
* private/protected/public.
*/
class MemberInfo
{
public:
MemberInfo() : _declaration(0), _name(), _type(ClassInfo::PRIVATE)
{
}
virtual ~MemberInfo() {}
const Token *_declaration;
std::string _name;
ClassInfo::MemberType _type;
};
/**
* Information about a single member function of a class.
*/
class MemberFunctionInfo : public MemberInfo
{
public:
MemberFunctionInfo() : _implementation(0)
{
}
const Token *_implementation;
};
/**
* Information about a single member variable of a class.
*/
class MemberVariableInfo : public MemberInfo
{
};
/**
* List of member functions
*/
std::vector<MemberFunctionInfo> _memberFunctions;
/**
* List of member variables
*/
std::vector<MemberVariableInfo> _memberVariables;
};
/// @}
//---------------------------------------------------------------------------
#endif

View File

@ -725,6 +725,70 @@ void Tokenizer::simplifyTemplates()
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void Tokenizer::updateClassList()
{
const char pattern_class[] = "class %var% [{:]";
_classInfoList.clear();
// Locate class
const Token *tok1 = tokens();
while ((tok1 = Token::findmatch(tok1, pattern_class)))
{
const char *className;
className = tok1->strAt(1);
tok1 = tok1->next();
ClassInfo::MemberType memberType = ClassInfo::PRIVATE;
int indentlevel = 0;
for (const Token *tok = tok1; tok; tok = tok->next())
{
// Indentation
if (tok->str() == "{")
{
++indentlevel;
continue;
}
else if (tok->str() == "}")
{
--indentlevel;
if (indentlevel <= 0)
break;
continue;
}
// Parse class contents (indentlevel == 1)..
if (indentlevel == 1)
{
if (tok->str() == "private:")
memberType = ClassInfo::PRIVATE;
else if (tok->str() == "protected:")
memberType = ClassInfo::PROTECTED;
else if (tok->str() == "public:")
memberType = ClassInfo::PUBLIC;
else if (Token::Match(tok, "typedef %type% ("))
tok = tok->tokAt(2);
else if (Token::Match(tok, "[:,] %var% ("))
tok = tok->tokAt(2);
else if (Token::Match(tok, "%var% ("))
{
// member function
ClassInfo::MemberFunctionInfo func;
func._declaration = tok;
func._name = tok->str();
func._type = memberType;
_classInfoList[className]._memberFunctions.push_back(func);
}
}
}
}
}
void Tokenizer::setVarId() void Tokenizer::setVarId()
{ {

View File

@ -25,6 +25,7 @@
#include <string> #include <string>
#include <map> #include <map>
#include <vector> #include <vector>
#include "classinfo.h"
class Token; class Token;
class ErrorLogger; class ErrorLogger;
@ -105,6 +106,12 @@ public:
*/ */
static const Token *findClassFunction(const Token *tok, const char classname[], const char funcname[], int &indentlevel); static const Token *findClassFunction(const Token *tok, const char classname[], const char funcname[], int &indentlevel);
/**
* List of classes in currently checked source code and
* their member functions and member variables.
*/
std::map<std::string, ClassInfo> _classInfoList;
private: private:
/** /**
@ -280,6 +287,12 @@ private:
void syntaxError(const Token *tok, char c); void syntaxError(const Token *tok, char c);
/**
* Update _classInfoList to contain class names and member
* functions and member variables.
*/
void updateClassList();
Token *_tokens, *_tokensBack; Token *_tokens, *_tokensBack;
std::map<std::string, unsigned int> _typeSize; std::map<std::string, unsigned int> _typeSize;
std::vector<std::string> _files; std::vector<std::string> _files;

View File

@ -143,6 +143,7 @@ private:
// unsigned i; => unsigned int i; // unsigned i; => unsigned int i;
TEST_CASE(unsigned1); TEST_CASE(unsigned1);
TEST_CASE(testUpdateClassList);
} }
@ -2387,6 +2388,38 @@ private:
} }
void tokenizeAndUpdateClassList(const char code[])
{
// tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.updateClassList();
}
void testUpdateClassList()
{
const char code[] = "class A{\n"
" void f() {}\n"
" public:\n"
" void g() {}\n"
"};";
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.updateClassList();
ASSERT_EQUALS(2, tokenizer._classInfoList["A"]._memberFunctions.size());
if (tokenizer._classInfoList["A"]._memberFunctions.size() > 1)
{
ASSERT_EQUALS(std::string("f"), tokenizer._classInfoList["A"]._memberFunctions[0]._name);
ASSERT_EQUALS(std::string("f"), tokenizer._classInfoList["A"]._memberFunctions[0]._declaration->str());
ASSERT_EQUALS(ClassInfo::PRIVATE, tokenizer._classInfoList["A"]._memberFunctions[0]._type);
ASSERT_EQUALS(std::string("g"), tokenizer._classInfoList["A"]._memberFunctions[1]._name);
ASSERT_EQUALS(std::string("g"), tokenizer._classInfoList["A"]._memberFunctions[1]._declaration->str());
ASSERT_EQUALS(ClassInfo::PUBLIC, tokenizer._classInfoList["A"]._memberFunctions[1]._type);
}
}
}; };
REGISTER_TEST(TestTokenizer) REGISTER_TEST(TestTokenizer)