data: function signature handling

* functions will only display their names in the graph view. hovering the nodes shows the signature as a tooltip. However, nodes in the database will be created and used regarding their signature.
* improved lambda handling. All calls to generated lambda functions (constructor, call operator) will now point to the lambda class instead.
* implemented handling of the "auto" type.
* improved the CxxParserTestSuite to use function strings instead of function names for template related functions.
This commit is contained in:
malte_langkabel
2015-12-16 11:27:29 +01:00
parent 28c1a0048b
commit a44af51122
8 changed files with 118 additions and 71 deletions
+14 -16
View File
@@ -433,24 +433,20 @@ std::vector<StorageEdge> SqliteStorage::getEdgesByTargetType(Id targetId, int ty
StorageNode SqliteStorage::getNodeById(Id id) const
{
std::vector<StorageNode> nodes = getAllNodes("WHERE id == " + std::to_string(id));
if (nodes.size())
if (id != 0)
{
return nodes[0];
std::vector<StorageNode> nodes = getAllNodes("WHERE id == " + std::to_string(id));
if (nodes.size())
{
return nodes[0];
}
}
return StorageNode(0, 0, 0, false);
}
StorageNode SqliteStorage::getNodeByNameId(Id nameId) const
std::vector<StorageNode> SqliteStorage::getNodesByNameId(Id nameId) const
{
std::vector<StorageNode> nodes = getAllNodes("WHERE name_id == " + std::to_string(nameId));
if (nodes.size())
{
return nodes[0];
}
return StorageNode(0, 0, 0, false);
return getAllNodes("WHERE name_id == " + std::to_string(nameId));
}
std::vector<StorageNode> SqliteStorage::getNodesByIds(const std::vector<Id>& nodeIds) const
@@ -736,18 +732,20 @@ std::vector<StorageComponentAccess> SqliteStorage::getComponentAccessByMemberEdg
return accesses;
}
Id SqliteStorage::getNodeIdBySignature(const std::string& signature) const
std::vector<Id> SqliteStorage::getNodeIdsBySignature(const std::string& signature) const
{
CppSQLite3Query q = m_database.execQuery((
"SELECT id, signature FROM function_signature WHERE signature == '" + signature + "';"
"SELECT id FROM function_signature WHERE signature == '" + signature + "';"
).c_str());
std::vector<Id> ids;
while (!q.eof())
{
return q.getIntField(0, 0);
ids.push_back(q.getIntField(0, 0));
q.nextRow();
}
return 0;
return ids;
}
std::string SqliteStorage::getSignatureByNodeId(Id nodeId) const
+2 -2
View File
@@ -78,7 +78,7 @@ public:
std::vector<StorageEdge> getEdgesByTargetType(Id targetId, int type) const;
StorageNode getNodeById(Id id) const;
StorageNode getNodeByNameId(Id nameId) const;
std::vector<StorageNode> getNodesByNameId(Id nameId) const;
std::vector<StorageNode> getNodesByIds(const std::vector<Id>& nodeIds) const;
StorageFile getFileById(const Id id) const;
@@ -107,7 +107,7 @@ public:
StorageComponentAccess getComponentAccessByMemberEdgeId(Id memberEdgeId) const;
std::vector<StorageComponentAccess> getComponentAccessByMemberEdgeIds(const std::vector<Id>& memberEdgeIds) const;
Id getNodeIdBySignature(const std::string& signature) const;
std::vector<Id> getNodeIdsBySignature(const std::string& signature) const;
std::string getSignatureByNodeId(Id nodeId) const;
std::vector<StorageCommentLocation> getCommentLocationsInFile(const FilePath& filePath) const;
+59 -9
View File
@@ -772,7 +772,12 @@ Id Storage::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) co
currentId = m_sqliteStorage.getNameHierarchyElementIdByName(nameHierarchy[i]->getFullName(), currentId);
}
return m_sqliteStorage.getNodeByNameId(currentId).id;
std::vector<StorageNode> nodes = m_sqliteStorage.getNodesByNameId(currentId);
if (nodes.size() > 0) // TODO: make it impossible that one name id referrs to n nodes.
{
return nodes[0].id;
}
return 0;
}
Id Storage::getIdForEdge(
@@ -1307,24 +1312,64 @@ Id Storage::addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarch
for (size_t i = 0; i < nameIds.size(); i++)
{
Id nameId = nameIds[i];
bool lastName = (i == nameHierarchy.size() - 1);
const bool isLastElement = (i == nameHierarchy.size() - 1);
const std::string& signature = nameHierarchy[i]->getFullSignature();
const bool hasSignature = (signature.size() > 0);
Node::NodeType type = (lastName ? nodeType : Node::NODE_UNDEFINED);
Node::NodeType type = (isLastElement ? nodeType : Node::NODE_UNDEFINED);
StorageNode node(0, 0, 0, false);
if (hasSignature)
{
std::vector<Id> potentialIds = m_sqliteStorage.getNodeIdsBySignature(signature);
if (parentNodeId != 0)
{
for (size_t i = 0; i < potentialIds.size(); i++)
{
if (m_sqliteStorage.getEdgeBySourceTargetType(parentNodeId, potentialIds[i], Edge::EDGE_MEMBER).id != 0)
{
node = m_sqliteStorage.getNodeById(potentialIds[i]);
break;
}
}
}
else if (potentialIds.size() > 0)
{
node = m_sqliteStorage.getNodeById(potentialIds[0]);
}
}
else
{
std::vector<StorageNode> potentialIds = m_sqliteStorage.getNodesByNameId(nameId);
if (parentNodeId != 0)
{
for (size_t i = 0; i < potentialIds.size(); i++)
{
if (m_sqliteStorage.getEdgeBySourceTargetType(parentNodeId, potentialIds[i].id, Edge::EDGE_MEMBER).id != 0)
{
node = potentialIds[i];
break;
}
}
}
else if (potentialIds.size() > 0)
{
node = potentialIds[0];
}
}
const StorageNode node = m_sqliteStorage.getNodeByNameId(nameId);
Id nodeId = node.id;
if (nodeId && !node.defined && lastName && defined)
if (nodeId && !node.defined && isLastElement && defined)
{
m_sqliteStorage.setNodeDefined(true, nodeId);
}
if (nodeId == 0)
{
nodeId = m_sqliteStorage.addNode(Node::typeToInt(type), nameId, lastName && defined);
nodeId = m_sqliteStorage.addNode(Node::typeToInt(type), nameId, isLastElement && defined);
std::string signature = nameHierarchy[i]->getFullSignature();
if (signature.size() != 0)
if (hasSignature)
{
m_sqliteStorage.addSignature(nodeId, signature);
}
@@ -1334,7 +1379,7 @@ Id Storage::addNodeHierarchy(Node::NodeType nodeType, NameHierarchy nameHierarch
addEdge(parentNodeId, nodeId, Edge::EDGE_MEMBER);
}
}
else if (lastName) // Update the type of the last node if the new type is more specific.
else if (isLastElement) // Update the type of the last node if the new type is more specific.
{
Node::NodeType storedType = Node::intToType(node.type);
if (type > storedType)
@@ -1433,6 +1478,11 @@ Id Storage::addEdge(Id sourceNodeId, Id targetNodeId, Edge::EdgeType type)
Id Storage::addEdge(Id sourceNodeId, Id targetNodeId, Edge::EdgeType type, ParseLocation location)
{
if (!sourceNodeId || !targetNodeId)
{
return 0;
}
Id edgeId = addEdge(sourceNodeId, targetNodeId, type);
addSourceLocation(edgeId, location, false);
+2 -3
View File
@@ -107,10 +107,9 @@ std::string ParserClient::parameterStr(const std::vector<ParseTypeUsage> paramet
std::string ParserClient::functionStr(const ParseFunction& function)
{
//return function.getFullName();
std::string str =
function.returnType.dataType->getFullTypeName() + " " + function.getFullName();
return addStaticPrefix(str, function.isStatic);
function.returnType.dataType->getFullTypeName() + " " + function.getFullName() + parameterStr(function.parameters);
return addConstPrefix(addStaticPrefix(str, function.isStatic), function.isConst, false);
}
ParserClient::ParserClient()
@@ -40,10 +40,10 @@ NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy()
LOG_ERROR("unhandled declaration type: " + std::string(m_declaration->getDeclKindName()));
}
contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext());
if (declName)
{
contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext());
if ((clang::isa<clang::NonTypeTemplateParmDecl>(m_declaration) ||
clang::isa<clang::TemplateTypeParmDecl>(m_declaration) ||
clang::isa<clang::TemplateTemplateParmDecl>(m_declaration)) &&
@@ -58,11 +58,6 @@ NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy()
contextNameHierarchy.push(declName);
}
}
else
{
const clang::SourceManager& sourceManager = m_declaration->getASTContext().getSourceManager();
LOG_ERROR("could not resolve name of decl at: " + m_declaration->getLocation().printToString(sourceManager));
}
}
return contextNameHierarchy;
}
@@ -153,10 +148,12 @@ std::shared_ptr<NameElement> CxxDeclNameResolver::getDeclName()
}
else if (recordDecl->isLambda())
{
// return empty pointer since lambdas will be handled at the level of the individual functions... not optimal.
return std::shared_ptr<NameElement>();
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(recordDecl->getLocStart());
std::string lambdaName = "lambda at " + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn());
return std::make_shared<NameElement>(lambdaName, lambdaName);
}
else if (!recordDecl->isLambda() && declNameString.size() == 0)
else if (declNameString.size() == 0)
{
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
@@ -170,10 +167,8 @@ std::shared_ptr<NameElement> CxxDeclNameResolver::getDeclName()
{
if (methodDecl->getParent()->isLambda())
{
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(methodDecl->getParent()->getLocStart());
std::string lambdaName = "lambda at " + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn());
return std::make_shared<NameElement>(lambdaName, lambdaName);
// return empty pointer since lambdas will be handled at the level of the parent class... not optimal.
return std::shared_ptr<NameElement>();
}
}
@@ -229,7 +224,7 @@ std::shared_ptr<NameElement> CxxDeclNameResolver::getDeclName()
parameterString += ")";
return std::make_shared<NameElement>(
functionName + parameterString + (isConst ? "const" : ""),
functionName,
(isStatic ? "static " : "") + returnTypeString + " " + functionName + parameterString + (isConst ? " const" : ""));
}
@@ -178,6 +178,12 @@ std::shared_ptr<DataType> CxxTypeNameResolver::typeToDataType(const clang::Type*
dataType = qualTypeToDataType(packExpansionType->getPattern());
break;
}
case clang::Type::Auto:
{
const clang::AutoType* autoType = clang::dyn_cast<clang::AutoType>(type);
dataType = qualTypeToDataType(autoType->getDeducedType());
break;
}
default:
{
LOG_INFO(std::string("Unhandled kind of type encountered: ") + type->getTypeClassName());
+22 -23
View File
@@ -138,8 +138,8 @@ public:
);
TS_ASSERT_EQUALS(client->structs.size(), 2);
TS_ASSERT_EQUALS(client->structs[0], "foo(int)::B <3:2 <3:9 3:9> 5:2>");
TS_ASSERT_EQUALS(client->structs[1], "foo(float)::B <9:2 <9:9 9:9> 11:2>");
TS_ASSERT_EQUALS(client->structs[0], "foo::B <3:2 <3:9 3:9> 5:2>");
TS_ASSERT_EQUALS(client->structs[1], "foo::B <9:2 <9:9 9:9> 11:2>");
}
void test_cxx_parser_finds_variable_definitions_in_global_scope()
@@ -328,7 +328,7 @@ public:
);
TS_ASSERT_EQUALS(client->methods.size(), 1);
TS_ASSERT_EQUALS(client->methods[0], "private bool B::C::isGreat()const <5:8 5:14>");
TS_ASSERT_EQUALS(client->methods[0], "private bool B::C::isGreat() const <5:8 5:14>");
}
void test_cxx_parser_finds_named_namespace()
@@ -1810,7 +1810,7 @@ public:
"}\n"
);
TS_ASSERT_EQUALS(client->templateMemberSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateMemberSpecializations[0], "A<int>::foo() -> A<typename T>::foo() <0:0 0:0>");
TS_ASSERT_EQUALS(client->templateMemberSpecializations[0], "int A<int>::foo() -> A<typename T>::T A<typename T>::foo() <0:0 0:0>");
}
void test_cxx_parser_finds_explicit_template_specialization()
@@ -2529,7 +2529,7 @@ public:
);
TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateSpecializations[0], "test<int>(int) -> test<typename T> <2:3 2:6>");
TS_ASSERT_EQUALS(client->templateSpecializations[0], "int test<int>(int) -> test<typename T>::T test<typename T>(test<typename T>::T) <2:3 2:6>");
}
void test_cxx_parser_finds_explicit_specialization_of_template_function()
@@ -2549,7 +2549,7 @@ public:
);
TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateSpecializations[0], "test<int>(int) -> test<typename T> <8:5 8:8>");
TS_ASSERT_EQUALS(client->templateSpecializations[0], "int test<int>(int) -> test<typename T>::T test<typename T>(test<typename T>::T) <8:5 8:8>");
}
void test_cxx_parser_finds_explicit_type_template_argument_of_explicit_specialization_of_template_function()
@@ -2566,7 +2566,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<int>()->int <7:11 7:11>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test<int>()->int <7:11 7:11>");
}
void test_cxx_parser_finds_explicit_type_template_argument_of_function_call_in_function()
@@ -2582,7 +2582,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<int>()->int <6:7 6:7>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test<int>()->int <6:7 6:7>");
}
void test_cxx_parser_finds_explicit_non_type_template_argument_of_function_call_in_function()
@@ -2598,7 +2598,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<33>()->int <6:7 6:7>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test<33>()->int <6:7 6:7>");
}
void test_cxx_parser_finds_explicit_template_template_argument_of_function_call_in_function()
@@ -2615,7 +2615,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<A>()->A<typename T> <7:7 7:7>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test<A>()->A<typename T> <7:7 7:7>");
}
void test_cxx_parser_finds_implicit_type_template_argument_of_function_call_in_function()
@@ -2631,7 +2631,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<int>(int)->int <6:5 6:5>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "void test<int>(int)->int <6:5 6:5>");
}
void test_cxx_parser_finds_explicit_type_template_argument_of_function_call_in_var_decl()
@@ -2646,7 +2646,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<int>()->int <6:17 6:17>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "int test<int>()->int <6:17 6:17>");
}
void test_cxx_parser_finds_implicit_type_template_argument_of_function_call_in_var_decl()
@@ -2661,7 +2661,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<int>(int)->int <6:15 6:15>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "int test<int>(int)->int <6:15 6:15>");
}
@@ -2726,9 +2726,9 @@ public:
TS_ASSERT_EQUALS(client->functions.size(), 2);
TS_ASSERT_EQUALS(client->functions[0], "void lambdaCaller() <1:1 <1:6 1:17> 4:1>");
TS_ASSERT_EQUALS(client->functions[1], "void lambdaCaller()::lambda at 3:2 <3:5 <3:2 3:2> 3:7>");
TS_ASSERT_EQUALS(client->functions[1], "void lambdaCaller::lambda at 3:2() const <3:5 <3:2 3:2> 3:7>");
TS_ASSERT_EQUALS(client->calls.size(), 1);
TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller()::lambda at 3:2 <3:2 3:9>");
TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller::lambda at 3:2() const <3:2 3:9>");
}
void test_cxx_parser_ignores_lambda_in_function_but_still_finds_call_within()
@@ -2747,10 +2747,10 @@ public:
TS_ASSERT_EQUALS(client->functions.size(), 3);
TS_ASSERT_EQUALS(client->functions[0], "void func() <1:1 <1:6 1:9> 1:14>");
TS_ASSERT_EQUALS(client->functions[1], "void lambdaCaller() <2:1 <2:6 2:17> 8:1>");
TS_ASSERT_EQUALS(client->functions[2], "void lambdaCaller()::lambda at 4:2 <4:5 <4:2 4:2> 7:2>");
TS_ASSERT_EQUALS(client->functions[2], "void lambdaCaller::lambda at 4:2() const <4:5 <4:2 4:2> 7:2>");
TS_ASSERT_EQUALS(client->calls.size(), 2);
TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller()::lambda at 4:2 <4:2 7:4>");
TS_ASSERT_EQUALS(client->calls[1], "void lambdaCaller()::lambda at 4:2 -> void func() <6:3 6:8>");
TS_ASSERT_EQUALS(client->calls[0], "void lambdaCaller() -> void lambdaCaller::lambda at 4:2() const <4:2 7:4>");
TS_ASSERT_EQUALS(client->calls[1], "void lambdaCaller::lambda at 4:2() const -> void func() <6:3 6:8>");
}
void test_cxx_parser_parses_multiple_files()
@@ -3056,7 +3056,7 @@ private:
const ParseFunction& templateFunction)
{
templateArgumentTypes.push_back(
addLocationSuffix(templateFunction.getFullName() + "->" + argumentTypeNameHierarchy.getFullName(), location)
addLocationSuffix(functionStr(templateFunction) + "->" + argumentTypeNameHierarchy.getFullName(), location)
);
return 0;
}
@@ -3094,9 +3094,8 @@ private:
virtual Id onTemplateMemberFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction)
{
// needs to be implemented
templateMemberSpecializations.push_back(addLocationSuffix(
instantiatedFunction.getFullName() + " -> " + specializedFunction.getFullName(), location
functionStr(instantiatedFunction) + " -> " + functionStr(specializedFunction), location
));
return 0;
}
@@ -3106,7 +3105,7 @@ private:
const ParseFunction function)
{
templateParameterTypes.push_back(
addLocationSuffix(templateParameterTypeNameHierarchy.getFullName(), location)
addLocationSuffix(templateParameterTypeNameHierarchy.getFullName(), location) // TODO: add template function!
);
return 0;
}
@@ -3115,7 +3114,7 @@ private:
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction)
{
templateSpecializations.push_back(
addLocationSuffix(specializedFunction.getFullName() + " -> " + templateFunction.getFullName(), location)
addLocationSuffix(functionStr(specializedFunction) + " -> " + functionStr(templateFunction), location)
);
return 0;
}
+3 -3
View File
@@ -310,15 +310,15 @@ public:
{
TestStorage storage;
ParseFunction a(typeUsage("void"), createNameHierarchy("A::isMethod(bool)"), parameters("bool"));
ParseFunction b(typeUsage("void"), createNameHierarchy("B::isMethod(bool)"), parameters("bool"));
ParseFunction a(typeUsage("void"), createNameHierarchy("A::isMethod"), parameters("bool"));
ParseFunction b(typeUsage("void"), createNameHierarchy("B::isMethod"), parameters("bool"));
storage.onMethodParsed(validLocation(9), a, ParserClient::ACCESS_PRIVATE, ParserClient::ABSTRACTION_VIRTUAL, validLocation(4));
storage.onMethodParsed(validLocation(7), b, ParserClient::ACCESS_PRIVATE, ParserClient::ABSTRACTION_NONE, validLocation(3));
storage.onMethodOverrideParsed(validLocation(4), a, b);
TS_ASSERT(storage.getEdgeId(Edge::EDGE_OVERRIDE, "B::isMethod(bool)", "A::isMethod(bool)") != 0);
TS_ASSERT(storage.getEdgeId(Edge::EDGE_OVERRIDE, "B::isMethod", "A::isMethod") != 0);
}
void test_storage_saves_call()