From 4f8a06ed0dcafdf372f10e6f87ef5a8f90438c7a Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Wed, 12 Aug 2009 23:50:03 +0300 Subject: [PATCH] Initial work for class and member function/variable list in tokenizer. --- cppcheck.cbp | 1 + src/classinfo.h | 96 +++++++++++++++++++++++++++++++++++++++++++ src/tokenize.cpp | 64 +++++++++++++++++++++++++++++ src/tokenize.h | 13 ++++++ test/testtokenize.cpp | 33 +++++++++++++++ 5 files changed, 207 insertions(+) create mode 100644 src/classinfo.h diff --git a/cppcheck.cbp b/cppcheck.cbp index 676dc3321..544b2772f 100644 --- a/cppcheck.cbp +++ b/cppcheck.cbp @@ -87,6 +87,7 @@ + diff --git a/src/classinfo.h b/src/classinfo.h new file mode 100644 index 000000000..2a20bfeb0 --- /dev/null +++ b/src/classinfo.h @@ -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 +#include +#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 _memberFunctions; + + /** + * List of member variables + */ + std::vector _memberVariables; +}; + + +/// @} + +//--------------------------------------------------------------------------- +#endif diff --git a/src/tokenize.cpp b/src/tokenize.cpp index e74ec9457..7e7aaa6ec 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -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() { diff --git a/src/tokenize.h b/src/tokenize.h index 3bc493dcc..23c75a02b 100644 --- a/src/tokenize.h +++ b/src/tokenize.h @@ -25,6 +25,7 @@ #include #include #include +#include "classinfo.h" class Token; class ErrorLogger; @@ -105,6 +106,12 @@ public: */ 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 _classInfoList; + private: /** @@ -280,6 +287,12 @@ private: void syntaxError(const Token *tok, char c); + /** + * Update _classInfoList to contain class names and member + * functions and member variables. + */ + void updateClassList(); + Token *_tokens, *_tokensBack; std::map _typeSize; std::vector _files; diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 7a5d1d900..67df16d14 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -143,6 +143,7 @@ private: // unsigned i; => unsigned int i; 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)