This change parses calls in CxxParser by using the class ASTBodyVisitor which traverses the Stmts and Exprs in the body of the function and method declarations. The calls include: * calls in functions * calls in methods * constructor calls * constructor calls in initialization lists * implicit constructor calls of fields * calls to operators * global constructor calls of global variables * global function calls for global variables The calls don't include: * destructor calls * some calls to implicit constructors and copy constructors fortune cookie message = Don't be afraid to take that big step.
991 lines
27 KiB
C++
991 lines
27 KiB
C++
#include "cxxtest/TestSuite.h"
|
|
|
|
#include <sstream>
|
|
|
|
#include "data/parser/cxx/CxxParser.h"
|
|
#include "data/parser/ParseLocation.h"
|
|
#include "data/parser/ParserClient.h"
|
|
#include "data/parser/ParseVariable.h"
|
|
#include "utility/text/TextAccess.h"
|
|
|
|
class CxxParserTestSuite: public CxxTest::TestSuite
|
|
{
|
|
public:
|
|
void test_cxx_parser_finds_global_class_definition()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A\n"
|
|
"{\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->classes.size(), 1);
|
|
TS_ASSERT_EQUALS(client->classes[0], "A <1:1 3:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_global_class_forward_declaration()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A;\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->classes.size(), 1);
|
|
TS_ASSERT_EQUALS(client->classes[0], "A <1:1 1:7>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_nested_class_definition() // TODO: test different access types here
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" class B;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->classes.size(), 2);
|
|
TS_ASSERT_EQUALS(client->classes[0], "A <1:1 5:1>");
|
|
TS_ASSERT_EQUALS(client->classes[1], "public A::B <4:2 4:8>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_class_definition_in_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace a\n"
|
|
"{\n"
|
|
" class B;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->classes.size(), 1);
|
|
TS_ASSERT_EQUALS(client->classes[0], "a::B <3:2 3:8>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_global_struct_definition()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"struct A\n"
|
|
"{\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->structs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->structs[0], "A <1:1 3:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_global_struct_forward_declaration()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"struct A;\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->structs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->structs[0], "A <1:1 1:8>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_struct_definition_in_class()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A\n"
|
|
"{\n"
|
|
" struct B\n"
|
|
" {\n"
|
|
" };\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->structs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->structs[0], "private A::B <3:2 5:2>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_struct_definition_in_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace A\n"
|
|
"{\n"
|
|
" struct B\n"
|
|
" {\n"
|
|
" };\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->structs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->structs[0], "A::B <3:2 5:2>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_variable_definitions_in_global_scope()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int x;\n"
|
|
"class A;\n"
|
|
"A* b;";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->globalVariables.size(), 2);
|
|
TS_ASSERT_EQUALS(client->globalVariables[0], "int x <1:1 1:5>");
|
|
TS_ASSERT_EQUALS(client->globalVariables[1], "A * b <3:1 3:4>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_variable_definitions_in_namespace_scope()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace n"
|
|
"{\n"
|
|
" int x;\n"
|
|
" class A;\n"
|
|
" A* b;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->globalVariables.size(), 2);
|
|
TS_ASSERT_EQUALS(client->globalVariables[0], "int n::x <2:2 2:6>");
|
|
TS_ASSERT_EQUALS(client->globalVariables[1], "n::A * n::b <4:2 4:5>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_field_in_nested_class()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" class C\n"
|
|
" {\n"
|
|
" private:\n"
|
|
" static const int amount;\n"
|
|
" };\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->fields.size(), 1);
|
|
TS_ASSERT_EQUALS(client->fields[0], "private static const int B::C::amount <7:3 7:20>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_field_in_global_class()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" B() : count(0) {};\n"
|
|
"private:\n"
|
|
" const int count;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->fields.size(), 1);
|
|
TS_ASSERT_EQUALS(client->fields[0], "private const int B::count <6:2 6:12>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_function_in_global_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int ceil(float a)\n"
|
|
"{\n"
|
|
" return static_cast<int>(a) + 1;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->functions.size(), 1);
|
|
TS_ASSERT_EQUALS(client->functions[0], "int ceil(float a) <1:1 4:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_function_in_anonymous_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace\n"
|
|
"{\n"
|
|
" int sum(int a, int b);\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->functions.size(), 1);
|
|
TS_ASSERT_EQUALS(client->functions[0], "int (anonymous namespace)::sum(int a, int b) <3:2 3:22>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_method_declaration()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" B();\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->methods.size(), 1);
|
|
TS_ASSERT_EQUALS(client->methods[0], "public void B::B() <4:2 4:4>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_method_declaration_and_definition()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" B();\n"
|
|
"};\n"
|
|
"B::B()\n"
|
|
"{\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->methods.size(), 2);
|
|
TS_ASSERT_EQUALS(client->methods[0], "public void B::B() <4:2 4:4>");
|
|
TS_ASSERT_EQUALS(client->methods[1], "public void B::B() <6:1 8:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_pure_virtual_method()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
"protected:\n"
|
|
" virtual void process() = 0;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->methods.size(), 1);
|
|
TS_ASSERT_EQUALS(client->methods[0], "protected pure virtual void B::process() <4:2 4:27>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_method_declared_in_nested_class()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
" class C\n"
|
|
" {\n"
|
|
" bool isGreat() const;\n"
|
|
" };\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->methods.size(), 1);
|
|
TS_ASSERT_EQUALS(client->methods[0], "private _Bool B::C::isGreat() const <5:3 5:18>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_named_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace A\n"
|
|
"{\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->namespaces.size(), 1);
|
|
TS_ASSERT_EQUALS(client->namespaces[0], "A <1:1 3:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_anonymous_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace\n"
|
|
"{\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->namespaces.size(), 1);
|
|
TS_ASSERT_EQUALS(client->namespaces[0], "(anonymous) <1:1 3:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_enum_defined_in_global_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"enum E\n"
|
|
"{\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->enums.size(), 1);
|
|
TS_ASSERT_EQUALS(client->enums[0], "E <1:1 3:1>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_enum_defined_in_class()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class B\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" enum Z\n"
|
|
" {\n"
|
|
" };\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->enums.size(), 1);
|
|
TS_ASSERT_EQUALS(client->enums[0], "public B::Z <4:2 6:2>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_enum_defined_in_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace n\n"
|
|
"{\n"
|
|
" enum Z\n"
|
|
" {\n"
|
|
" };\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->enums.size(), 1);
|
|
TS_ASSERT_EQUALS(client->enums[0], "n::Z <3:2 5:2>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_enum_field_in_global_enum()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"enum E\n"
|
|
"{\n"
|
|
" P\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->enumFields.size(), 1);
|
|
TS_ASSERT_EQUALS(client->enumFields[0], "E::P <3:2 3:2>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_typedef_in_global_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text = "typedef unsigned int uint;\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> uint <1:1 1:22>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_typedef_in_named_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace test\n"
|
|
"{\n"
|
|
" typedef unsigned int uint;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> test::uint <3:2 3:23>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_typedef_in_anonymous_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace\n"
|
|
"{\n"
|
|
" typedef unsigned int uint;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> (anonymous namespace)::uint <3:2 3:23>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_typedef_that_uses_type_defined_in_named_namespace()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"namespace test\n"
|
|
"{\n"
|
|
" struct TestStruct{};\n"
|
|
"}\n"
|
|
"typedef test::TestStruct globalTestStruct;\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->typedefs[0], "test::TestStruct -> globalTestStruct <5:1 5:26>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_public_inheritance()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A {};\n"
|
|
"class B : public A {};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
|
TS_ASSERT_EQUALS(client->inheritances[0], "B : public A <2:11 2:18>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_protected_inheritance()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A {};\n"
|
|
"class B : protected A {};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
|
TS_ASSERT_EQUALS(client->inheritances[0], "B : protected A <2:11 2:21>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_private_inheritance()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A {};\n"
|
|
"class B : private A {};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
|
TS_ASSERT_EQUALS(client->inheritances[0], "B : private A <2:11 2:19>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_multiple_inheritance()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class A {};\n"
|
|
"class B {};\n"
|
|
"class C\n"
|
|
" : public A\n"
|
|
" , private B\n"
|
|
"{};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->inheritances.size(), 2);
|
|
TS_ASSERT_EQUALS(client->inheritances[0], "C : public A <4:4 4:11>");
|
|
TS_ASSERT_EQUALS(client->inheritances[1], "C : private B <5:4 5:12>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_call_in_function()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int sum(int a, int b)\n"
|
|
"{\n"
|
|
" return a + b;\n"
|
|
"}\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
" sum(1, 2);\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "main -> sum <7:2 7:10>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_call_within_call_in_function()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int sum(int a, int b)\n"
|
|
"{\n"
|
|
" return a + b;\n"
|
|
"}\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
" return sum(1, sum(2, 3));\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 2);
|
|
TS_ASSERT_EQUALS(client->calls[0], "main -> sum <7:9 7:25>");
|
|
TS_ASSERT_EQUALS(client->calls[1], "main -> sum <7:16 7:24>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_call_in_method()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int sum(int a, int b)\n"
|
|
"{\n"
|
|
" return a + b;\n"
|
|
"}\n"
|
|
"class App\n"
|
|
"{\n"
|
|
" int main()\n"
|
|
" {\n"
|
|
" return sum(1, 2);\n"
|
|
" }\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "App::main -> sum <9:10 9:18>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_constructor_call()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class App\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" App() {}\n"
|
|
"};\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
" App app;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "main -> App::App <8:6 8:6>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_constructor_without_definition_call()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class App\n"
|
|
"{\n"
|
|
"};\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
" App app;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "main -> App::App <6:6 6:6>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_constructor_call_of_field()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class Item\n"
|
|
"{\n"
|
|
"};\n"
|
|
"class App\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" App() {}\n"
|
|
" Item item;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "App::App -> Item::Item <7:2 7:2>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_constructor_call_of_field_in_initialization_list()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class Item\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" Item(int n) {}\n"
|
|
"};\n"
|
|
"class App\n"
|
|
"{\n"
|
|
" App()\n"
|
|
" : item(1)"
|
|
" {}\n"
|
|
" Item item;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "App::App -> Item::Item <9:5 9:11>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_function_call_within_constructor_call_of_field_in_initialization_list()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int one() { return 1; }\n"
|
|
"class Item\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" Item(int n) {}\n"
|
|
"};\n"
|
|
"class App\n"
|
|
"{\n"
|
|
" App()\n"
|
|
" : item(one())"
|
|
" {}\n"
|
|
" Item item;\n"
|
|
"};\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 2);
|
|
TS_ASSERT_EQUALS(client->calls[0], "App::App -> Item::Item <10:5 10:15>");
|
|
TS_ASSERT_EQUALS(client->calls[1], "App::App -> one <10:10 10:14>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_copy_constructor_call()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class App\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" App() {}\n"
|
|
" App(const App& other) {}\n"
|
|
"};\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
" App app;\n"
|
|
" App app2(app);\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 2);
|
|
TS_ASSERT_EQUALS(client->calls[0], "main -> App::App <9:6 9:6>");
|
|
TS_ASSERT_EQUALS(client->calls[1], "main -> App::App <10:6 10:14>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_global_constructor_call()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class App\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" App() {}\n"
|
|
"};\n"
|
|
"App app;\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "app -> App::App <6:5 6:5>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_global_function_call()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"int one() { return 1; }\n"
|
|
"int a = one();\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 1);
|
|
TS_ASSERT_EQUALS(client->calls[0], "a -> one <2:9 2:13>");
|
|
}
|
|
|
|
void test_cxx_parser_finds_operator_call()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
std::string text =
|
|
"class App\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" void operator+(int a)\n"
|
|
" {\n"
|
|
" }\n"
|
|
"};\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
" App app;\n"
|
|
" app + 2;\n"
|
|
"}\n";
|
|
|
|
parser.parseFile(TextAccess::createFromString(text));
|
|
|
|
TS_ASSERT_EQUALS(client->calls.size(), 2);
|
|
TS_ASSERT_EQUALS(client->calls[0], "main -> App::App <10:6 10:6>");
|
|
TS_ASSERT_EQUALS(client->calls[1], "main -> App::operator+ <11:2 11:8>");
|
|
}
|
|
|
|
void test_cxx_parser_parses_multiple_files()
|
|
{
|
|
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
|
|
CxxParser parser(client);
|
|
|
|
std::vector<std::string> filePaths;
|
|
filePaths.push_back("data/CxxParserTestSuite/header.h");
|
|
filePaths.push_back("data/CxxParserTestSuite/code.cpp");
|
|
parser.parseFiles(filePaths);
|
|
|
|
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
|
|
TS_ASSERT_EQUALS(client->classes.size(), 3);
|
|
TS_ASSERT_EQUALS(client->enums.size(), 1);
|
|
TS_ASSERT_EQUALS(client->enumFields.size(), 2);
|
|
TS_ASSERT_EQUALS(client->functions.size(), 2);
|
|
TS_ASSERT_EQUALS(client->fields.size(), 4);
|
|
TS_ASSERT_EQUALS(client->globalVariables.size(), 2);
|
|
TS_ASSERT_EQUALS(client->methods.size(), 5);
|
|
TS_ASSERT_EQUALS(client->namespaces.size(), 2);
|
|
TS_ASSERT_EQUALS(client->structs.size(), 1);
|
|
}
|
|
|
|
private:
|
|
class TestParserClient: public ParserClient
|
|
{
|
|
public:
|
|
virtual void onTypedefParsed(
|
|
const ParseLocation& location, const std::string& fullName, const std::string& underlyingFullName,
|
|
AccessType access
|
|
)
|
|
{
|
|
std::string str = addAccessPrefix(underlyingFullName + " -> " + fullName, access);
|
|
typedefs.push_back(addLocationSuffix(str, location));
|
|
}
|
|
|
|
virtual void onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
|
{
|
|
classes.push_back(addLocationSuffix(addAccessPrefix(fullName, access), location));
|
|
}
|
|
|
|
virtual void onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
|
{
|
|
structs.push_back(addLocationSuffix(addAccessPrefix(fullName, access), location));
|
|
}
|
|
|
|
virtual void onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable)
|
|
{
|
|
globalVariables.push_back(addLocationSuffix(variableStr(variable), location));
|
|
}
|
|
|
|
virtual void onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access)
|
|
{
|
|
fields.push_back(addLocationSuffix(addAccessPrefix(variableStr(variable), access), location));
|
|
}
|
|
|
|
virtual void onFunctionParsed(
|
|
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
|
const std::vector<ParseVariable>& parameters
|
|
)
|
|
{
|
|
std::string str = returnTypeName + " " + fullName + parameterStr(parameters);
|
|
functions.push_back(addLocationSuffix(str, location));
|
|
}
|
|
|
|
virtual void onMethodParsed(
|
|
const ParseLocation& location, const std::string& fullName, const std::string& returnTypeName,
|
|
const std::vector<ParseVariable>& parameters, AccessType access, AbstractionType abstraction,
|
|
bool isConst, bool isStatic
|
|
)
|
|
{
|
|
std::string str = returnTypeName + " " + fullName + parameterStr(parameters);
|
|
str = addStaticPrefix(addAbstractionPrefix(str, abstraction), isStatic);
|
|
str = addConstPrefix(addAccessPrefix(str, access), isConst, false);
|
|
str = addLocationSuffix(str, location);
|
|
methods.push_back(str);
|
|
}
|
|
|
|
virtual void onNamespaceParsed(const ParseLocation& location, const std::string& fullName)
|
|
{
|
|
namespaces.push_back(addLocationSuffix(fullName, location));
|
|
}
|
|
|
|
virtual void onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
|
|
{
|
|
enums.push_back(addLocationSuffix(addAccessPrefix(fullName, access), location));
|
|
}
|
|
|
|
virtual void onEnumFieldParsed(const ParseLocation& location, const std::string& fullName)
|
|
{
|
|
enumFields.push_back(addLocationSuffix(fullName, location));
|
|
}
|
|
|
|
virtual void onInheritanceParsed(
|
|
const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access)
|
|
{
|
|
std::string str = fullName + " : " + addAccessPrefix(baseName, access);
|
|
inheritances.push_back(addLocationSuffix(str, location));
|
|
}
|
|
|
|
virtual void onCallParsed(
|
|
const ParseLocation& location, const std::string& callerName, const std::string& calleeName)
|
|
{
|
|
calls.push_back(addLocationSuffix(callerName + " -> " + calleeName, location));
|
|
}
|
|
|
|
std::vector<std::string> typedefs;
|
|
std::vector<std::string> classes;
|
|
std::vector<std::string> enums;
|
|
std::vector<std::string> enumFields;
|
|
std::vector<std::string> functions;
|
|
std::vector<std::string> fields;
|
|
std::vector<std::string> globalVariables;
|
|
std::vector<std::string> methods;
|
|
std::vector<std::string> namespaces;
|
|
std::vector<std::string> structs;
|
|
std::vector<std::string> inheritances;
|
|
std::vector<std::string> calls;
|
|
|
|
private:
|
|
std::string addAccessPrefix(const std::string& str, AccessType access)
|
|
{
|
|
switch (access)
|
|
{
|
|
case ACCESS_PUBLIC:
|
|
return "public " + str;
|
|
case ACCESS_PROTECTED:
|
|
return "protected " + str;
|
|
case ACCESS_PRIVATE:
|
|
return "private " + str;
|
|
case ACCESS_NONE:
|
|
return str;
|
|
}
|
|
}
|
|
|
|
std::string addAbstractionPrefix(const std::string& str, AbstractionType abstraction)
|
|
{
|
|
switch (abstraction)
|
|
{
|
|
case ABSTRACTION_VIRTUAL:
|
|
return "virtual " + str;
|
|
case ABSTRACTION_PURE_VIRTUAL:
|
|
return "pure virtual " + str;
|
|
case ABSTRACTION_NONE:
|
|
return str;
|
|
}
|
|
}
|
|
|
|
std::string addStaticPrefix(const std::string& str, bool isStatic)
|
|
{
|
|
if (isStatic)
|
|
{
|
|
return "static " + str;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
std::string addConstPrefix(const std::string& str, bool isConst, bool atFront)
|
|
{
|
|
if (isConst)
|
|
{
|
|
return atFront ? "const " + str : str + " const";
|
|
}
|
|
return str;
|
|
}
|
|
|
|
std::string variableStr(const ParseVariable& variable)
|
|
{
|
|
std::string str = variable.typeName + " " + variable.fullName;
|
|
return addStaticPrefix(addConstPrefix(str, variable.isConst, true), variable.isStatic);
|
|
}
|
|
|
|
std::string parameterStr(const std::vector<ParseVariable> parameters)
|
|
{
|
|
std::string str = "(";
|
|
for (size_t i = 0; i < parameters.size(); i++)
|
|
{
|
|
str += variableStr(parameters[i]);
|
|
if (i < parameters.size() - 1)
|
|
{
|
|
str += ", ";
|
|
}
|
|
}
|
|
return str + ")";
|
|
}
|
|
|
|
std::string addLocationSuffix(const std::string& str, const ParseLocation& location)
|
|
{
|
|
std::stringstream ss;
|
|
ss << str << " <" << location.startLineNumber << ":" << location.startColumnNumber << " ";
|
|
ss << location.endLineNumber << ":" << location.endColumnNumber << ">";
|
|
return ss.str();
|
|
}
|
|
};
|
|
};
|