data: basic template parsing

* Implemented basic parsing and storage of template parameter types, template classes and template functions
* Added template specialization edge.
* Implemented handling of partial specializations. Needs some more tweaking.
* Added a lot of test code for template stuff (still needs some cases to be tested)
* Removed the isTemplateParameterType from DataType, since it shouldn't be needed
* Function qualTypeToDataType uses clang PrintingPolicy to fetch the desired format.
* Merged a lot of code for getting the correct names and name hierarchies of definitions
* Removed TokenComponentDataType
* Merged both of the Storage::addTypeEdge(...) functions
* Added "-fno-delayed-template-parsing" flag to parser for parsing test code.
This commit is contained in:
malte_langkabel
2014-11-24 16:50:31 +01:00
parent 7b17f5b3ad
commit 63407c2c81
24 changed files with 792 additions and 239 deletions
+345 -4
View File
@@ -324,7 +324,23 @@ public:
);
TS_ASSERT_EQUALS(client->namespaces.size(), 1);
TS_ASSERT_EQUALS(client->namespaces[0], "(anonymous) <1:1 3:1>");
TS_ASSERT_EQUALS(client->namespaces[0], "(anonymous namespace) <1:1 3:1>");
}
void test_cxx_parser_finds_nested_named_namespace()
{
std::shared_ptr<TestParserClient> client = parseCode(
"namespace A\n"
"{\n"
" namespace B\n"
" {\n"
" }\n"
"}\n"
);
TS_ASSERT_EQUALS(client->namespaces.size(), 2);
TS_ASSERT_EQUALS(client->namespaces[0], "A <1:1 <1:11 1:11> 6:1>");
TS_ASSERT_EQUALS(client->namespaces[1], "A::B <3:2 <3:12 3:12> 5:2>");
}
void test_cxx_parser_finds_enum_defined_in_global_namespace()
@@ -722,7 +738,7 @@ public:
TS_ASSERT_EQUALS(client->calls.size(), 2);
TS_ASSERT_EQUALS(client->calls[0], "int main() -> void App::App() <9:6 9:6>");
TS_ASSERT_EQUALS(client->calls[1], "int main() -> void App::App(class App const &) <10:6 10:14>");
TS_ASSERT_EQUALS(client->calls[1], "int main() -> void App::App(App const &) <10:6 10:14>");
}
void test_cxx_parser_finds_global_constructor_call()
@@ -974,6 +990,289 @@ public:
TS_ASSERT_EQUALS(client->typeUses[1], "void B::B() -> A <8:8 8:8>");
}
void test_cxx_parser_finds_template_parameter_type_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<T>::T <1:20 1:20>");
}
void test_cxx_parser_finds_template_parameter_type_of_template_class_with_multiple_parameters()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T, typename U>\n"
"class A\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<T, U>::T <1:20 1:20>");
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A<T, U>::U <1:32 1:32>");
}
void test_cxx_parser_finds_correct_field_member_name_of_template_class_in_declaration()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" int foo;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->fields.size(), 1);
TS_ASSERT_EQUALS(client->fields[0], "private int A<T>::foo <4:6 4:8>");
}
void test_cxx_parser_finds_correct_field_member_type_of_template_class_in_declaration()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" T foo;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->fields.size(), 1);
TS_ASSERT_EQUALS(client->fields[0], "private A<T>::T A<T>::foo <4:4 4:6>");
}
void test_cxx_parser_finds_template_class_specialization_with_non_template_argument()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" T foo;\n"
"};\n"
"\n"
"A<int> a\n"
);
TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A<int> -> A<T> <2:7 2:7>");
}
void test_cxx_parser_finds_class_inheritance_from_specialized_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" T foo;\n"
"};\n"
"\n"
"class B: public A<int>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
TS_ASSERT_EQUALS(client->inheritances[0], "B : public A<int> <7:10 7:22>");
}
//void _____test_cxx_parser_finds_template_class_specialization_with_template_argument()
//{
// std::shared_ptr<TestParserClient> client = parseCode(
// "template <typename T>\n"
// "class A\n"
// "{\n"
// " T foo;\n"
// "};\n"
// "\n"
// "template <typename U>\n"
// "class B: public A<U>\n"
// "{\n"
// "};\n"
// );
// TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
// TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A<U> -> A<T> <2:7 2:7>");
//}
void test_cxx_parser_finds_template_class_constructor_usage_of_field()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" A(): foo() {}\n"
" T foo;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->usages.size(), 1);
TS_ASSERT_EQUALS(client->usages[0], "void A<T>::A<T>() -> A<T>::foo <4:7 4:9>");
}
void test_cxx_parser_finds_enum_definition_in_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" Enum TestType\n"
" {\n"
" TEST_ONE\n"
" TEST_TWO\n"
" };\n"
"};\n"
);
TS_ASSERT_EQUALS(client->enums.size(), 1);
TS_ASSERT_EQUALS(client->enums[0], "private A<T>::TestType <4:2 <4:7 4:14> 8:2>");
}
void test_cxx_parser_finds_enum_usage_in_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" Enum TestType\n"
" {\n"
" TEST_ONE,\n"
" TEST_TWO\n"
" };\n"
" TestType foo;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->fields.size(), 1);
TS_ASSERT_EQUALS(client->fields[0], "private A<T>::TestType A<T>::foo <9:11 9:13>");
}
void test_cxx_parser_finds_enum_fields_in_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" Enum TestType\n"
" {\n"
" TEST_ONE,\n"
" TEST_TWO\n"
" };\n"
"};\n"
);
TS_ASSERT_EQUALS(client->enumFields.size(), 2);
TS_ASSERT_EQUALS(client->enumFields[0], "A<T>::TestType::TEST_ONE <6:3 6:3>");
TS_ASSERT_EQUALS(client->enumFields[1], "A<T>::TestType::TEST_TWO <7:3 7:3>");
}
//void _____test_cxx_parser_finds_correct_field_member_type_of_nested_template_class_in_declaration()
//{
// std::shared_ptr<TestParserClient> client = parseCode(
// "template <typename T>\n"
// "class A\n"
// "{\n"
// " class B\n"
// " {\n"
// " T foo;\n"
// " };\n"
// "};\n"
// );
// TS_ASSERT_EQUALS(client->fields.size(), 1);
// TS_ASSERT_EQUALS(client->fields[0], "private A<T>::T A<T>::B::foo <4:4 4:6>");
//}
void test_cxx_parser_finds_correct_method_member_name_of_template_class_in_declaration()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" int foo();\n"
"};\n"
);
TS_ASSERT_EQUALS(client->methods.size(), 1);
TS_ASSERT_EQUALS(client->methods[0], "private int A<T>::foo() <4:6 4:8>");
}
void test_cxx_parser_finds_correct_method_member_return_type_of_template_class_in_declaration()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
" T foo();\n"
"};\n"
);
TS_ASSERT_EQUALS(client->methods.size(), 1);
TS_ASSERT_EQUALS(client->methods[0], "private A<T>::T A<T>::foo() <4:4 4:6>");
}
void test_cxx_parser_finds_template_parameter_type_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"T test(T a)\n"
"{\n"
" return a;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test::T <1:20 1:20>");
}
void test_cxx_parser_finds_implicit_specialization_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"T test(T a)\n"
"{\n"
" return a;\n"
"};\n"
"\n"
"int main()\n"
"{\n"
" return test(1);\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateSpecializations[0], "test -> test <2:3 2:6>");
}
void test_cxx_parser_finds_explicit_specialization_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"T test(T a)\n"
"{\n"
" return a;\n"
"};\n"
"\n"
"template <>\n"
"int test<int>(int a)\n"
"{\n"
" return a + a;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateSpecializations[0], "test -> test <8:5 8:8>");
}
void test_cxx_parser_parses_multiple_files()
{
TestParserClient client;
@@ -1137,6 +1436,46 @@ private:
return 0;
}
virtual Id onTemplateRecordParameterTypeParsed(
const ParseLocation& location, const std::string& templateParameterTypeName,
const std::vector<std::string>& templateRecordNameHierarchy)
{
templateParameterTypes.push_back(
addLocationSuffix(utility::join(templateRecordNameHierarchy, "::") + "::" + templateParameterTypeName, location)
);
return 0;
}
virtual Id onTemplateRecordSpecializationParsed(
const ParseLocation& location, const std::vector<std::string>& specializedRecordNameHierarchy,
const RecordType specializedRecordType, const std::vector<std::string>& templateRecordNameHierarchy)
{
templateSpecializations.push_back(
addLocationSuffix(std::string(specializedRecordType == ParserClient::RECORD_CLASS ? "class" : "struct") + " " +
utility::join(specializedRecordNameHierarchy, "::") + " -> " + utility::join(templateRecordNameHierarchy, "::"), location)
);
return 0;
}
virtual Id onTemplateFunctionParameterTypeParsed(
const ParseLocation& location, const std::string& templateParameterTypeName,
const ParseFunction function)
{
templateParameterTypes.push_back(
addLocationSuffix(function.getFullName() + "::" + templateParameterTypeName, location)
);
return 0;
}
virtual Id onTemplateFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction)
{
templateSpecializations.push_back(
addLocationSuffix(specializedFunction.getFullName() + " -> " + templateFunction.getFullName(), location)
);
return 0;
}
std::vector<std::string> typedefs;
std::vector<std::string> classes;
std::vector<std::string> enums;
@@ -1150,8 +1489,10 @@ private:
std::vector<std::string> inheritances;
std::vector<std::string> calls;
std::vector<std::string> usages;
std::vector<std::string> typeUses;
std::vector<std::string> usages; // for variables
std::vector<std::string> typeUses; // for types
std::vector<std::string> templateParameterTypes;
std::vector<std::string> templateSpecializations;
private:
void addTypeUse(const ParseTypeUsage& use)
+9 -9
View File
@@ -10,14 +10,14 @@ class DataTypeTestSuite: public CxxTest::TestSuite
public:
void test_datatype_created_with_name_has_no_qualifiers_or_modifiers()
{
DataType dataType("int");
DataType dataType(utility::splitToVector("int", "::"));
TS_ASSERT_EQUALS("int", dataType.getFullTypeName());
}
void test_datatype_created_with_name_and_empty_qualifiers_has_no_qualifiers_or_modifiers()
{
DataTypeQualifierList qualifierList;
DataType dataType("int", qualifierList);
DataType dataType(utility::splitToVector("int", "::"), qualifierList);
TS_ASSERT_EQUALS("int", dataType.getFullTypeName());
}
@@ -25,7 +25,7 @@ public:
{
DataTypeQualifierList qualifierList;
qualifierList.addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
DataType dataType("int", qualifierList);
DataType dataType(utility::splitToVector("int", "::"), qualifierList);
TS_ASSERT_EQUALS("int const", dataType.getFullTypeName());
}
@@ -33,7 +33,7 @@ public:
{
DataTypeQualifierList qualifierList;
DataTypeModifierStack modifierStack;
DataType dataType("int", qualifierList, modifierStack);
DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack);
TS_ASSERT_EQUALS("int", dataType.getFullTypeName());
}
@@ -42,7 +42,7 @@ public:
DataTypeQualifierList qualifierList;
DataTypeModifierStack modifierStack;
modifierStack.push(std::make_shared<DataTypeModifierArray>());
DataType dataType("int", qualifierList, modifierStack);
DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack);
TS_ASSERT_EQUALS("int []", dataType.getFullTypeName());
}
@@ -51,7 +51,7 @@ public:
DataTypeQualifierList qualifierList;
DataTypeModifierStack modifierStack;
modifierStack.push(std::make_shared<DataTypeModifierPointer>());
DataType dataType("int", qualifierList, modifierStack);
DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack);
TS_ASSERT_EQUALS("int *", dataType.getFullTypeName());
}
@@ -60,7 +60,7 @@ public:
DataTypeQualifierList qualifierList;
DataTypeModifierStack modifierStack;
modifierStack.push(std::make_shared<DataTypeModifierReference>());
DataType dataType("int", qualifierList, modifierStack);
DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack);
TS_ASSERT_EQUALS("int &", dataType.getFullTypeName());
}
@@ -71,7 +71,7 @@ public:
std::shared_ptr<DataTypeModifier> modifier = std::make_shared<DataTypeModifierPointer>();
modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
modifierStack.push(modifier);
DataType dataType("int", qualifierList, modifierStack);
DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack);
TS_ASSERT_EQUALS("int * const", dataType.getFullTypeName());
}
@@ -81,7 +81,7 @@ public:
DataTypeModifierStack modifierStack;
modifierStack.push(std::make_shared<DataTypeModifierPointer>());
modifierStack.push(std::make_shared<DataTypeModifierPointer>());
DataType dataType("int", qualifierList, modifierStack);
DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack);
TS_ASSERT_EQUALS("int * *", dataType.getFullTypeName());
}
};
+1 -1
View File
@@ -560,7 +560,7 @@ private:
ParseTypeUsage typeUsage(const std::string& typeName) const
{
return ParseTypeUsage(validLocation(), DataType(typeName));
return ParseTypeUsage(validLocation(), DataType(utility::splitToVector(typeName, "::")));
}
std::vector<ParseTypeUsage> parameters(const std::string& param) const