Files
Sourcetrail/src/lib/data/Storage.cpp
T

628 lines
15 KiB
C++

#include "data/Storage.h"
#include "data/graph/token_component/TokenComponentConst.h"
#include "data/graph/token_component/TokenComponentDataType.h"
#include "data/graph/token_component/TokenComponentStatic.h"
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationFile.h"
#include "data/location/TokenLocationLine.h"
#include "data/parser/ParseLocation.h"
#include "data/parser/ParseTypeUsage.h"
#include "data/parser/ParseVariable.h"
#include "data/type/DataType.h"
#include "utility/logging/logging.h"
#include "utility/utilityString.h"
Storage::Storage()
{
}
Storage::~Storage()
{
}
void Storage::clear()
{
m_graph.clear();
m_locationCollection.clear();
}
void Storage::logGraph() const
{
LOG_INFO_STREAM(<< '\n' << m_graph);
}
void Storage::logLocations() const
{
LOG_INFO_STREAM(<< '\n' << m_locationCollection);
}
void Storage::onTypedefParsed(
const ParseLocation& location, const std::string& fullName, const DataType& underlyingType, AccessType access
){
log("typedef", fullName + " -> " + underlyingType.getFullTypeName(), location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_TYPEDEF, fullName);
addAccess(node, access);
addTokenLocation(node, location);
addTypeEdge(node, Edge::EDGE_TYPEDEF_OF, underlyingType);
}
void Storage::onClassParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
{
log("class", fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_CLASS, fullName);
addAccess(node, access);
addTokenLocation(node, location);
}
void Storage::onStructParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
{
log("struct", fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_STRUCT, fullName);
addAccess(node, access);
addTokenLocation(node, location);
}
void Storage::onGlobalVariableParsed(const ParseLocation& location, const ParseVariable& variable)
{
log("global", variable.fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_GLOBAL_VARIABLE, variable.fullName);
if (variable.isStatic)
{
node->addComponentStatic(std::make_shared<TokenComponentStatic>());
}
addTypeEdge(node, Edge::EDGE_TYPE_OF, variable.type);
addTokenLocation(node, location);
}
void Storage::onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access)
{
log("field", variable.fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_FIELD, variable.fullName);
if (variable.isStatic)
{
node->addComponentStatic(std::make_shared<TokenComponentStatic>());
}
if (access == ACCESS_NONE)
{
LOG_ERROR("Field needs to have access type [public, protected, private] but has none.");
return;
}
addAccess(node, access);
addTypeEdge(node, Edge::EDGE_TYPE_OF, variable.type);
addTokenLocation(node, location);
}
void Storage::onFunctionParsed(
const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType,
const std::vector<ParseTypeUsage>& parameters
)
{
log("function", fullName, location);
Node* node = m_graph.createNodeHierarchyWithDistinctSignature(
Node::NODE_FUNCTION, fullName,
ParserClient::functionSignatureStr(returnType.dataType, fullName, parameters, false)
);
addTokenLocation(node, location);
addTypeEdge(node, Edge::EDGE_RETURN_TYPE_OF, returnType);
for (const ParseTypeUsage& parameter : parameters)
{
addTypeEdge(node, Edge::EDGE_PARAMETER_TYPE_OF, parameter);
}
}
void Storage::onMethodParsed(
const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType,
const std::vector<ParseTypeUsage>& parameters, AccessType access, AbstractionType abstraction,
bool isConst, bool isStatic
)
{
log("method", fullName, location);
Node* node = m_graph.createNodeHierarchyWithDistinctSignature(
Node::NODE_METHOD, fullName,
ParserClient::functionSignatureStr(returnType.dataType, fullName, parameters, isConst)
);
if (isConst)
{
node->addComponentConst(std::make_shared<TokenComponentConst>());
}
if (isStatic)
{
node->addComponentStatic(std::make_shared<TokenComponentStatic>());
}
if (access == ACCESS_NONE)
{
LOG_ERROR("Method needs to have access type [public, protected, private] but has none.");
return;
}
addAccess(node, access);
addTokenLocation(node, location);
addTypeEdge(node, Edge::EDGE_RETURN_TYPE_OF, returnType);
for (const ParseTypeUsage& parameter : parameters)
{
addTypeEdge(node, Edge::EDGE_PARAMETER_TYPE_OF, parameter);
}
}
void Storage::onNamespaceParsed(const ParseLocation& location, const std::string& fullName)
{
log("namespace", fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_NAMESPACE, fullName);
addTokenLocation(node, location);
}
void Storage::onEnumParsed(const ParseLocation& location, const std::string& fullName, AccessType access)
{
log("enum", fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_ENUM, fullName);
addAccess(node, access);
addTokenLocation(node, location);
}
void Storage::onEnumFieldParsed(const ParseLocation& location, const std::string& fullName)
{
log("enum field", fullName, location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_FIELD, fullName);
addTokenLocation(node, location);
}
void Storage::onInheritanceParsed(
const ParseLocation& location, const std::string& fullName, const std::string& baseName, AccessType access)
{
log("inheritance", fullName + " : " + baseName, location);
Node* node = m_graph.createNodeHierarchy(fullName);
Node* baseNode = m_graph.createNodeHierarchy(baseName);
Edge* edge = m_graph.createEdge(Edge::EDGE_INHERITANCE, node, baseNode);
edge->addComponentAccess(std::make_shared<TokenComponentAccess>(convertAccessType(access)));
addTokenLocation(edge, location);
}
void Storage::onCallParsed(const ParseLocation& location, const std::string& callerName, const std::string& calleeName)
{
log("call", callerName + " -> " + calleeName, location);
Node* callerNode = m_graph.createNodeHierarchy(callerName);
Node* calleeNode = m_graph.createNodeHierarchy(calleeName);
Edge* edge = m_graph.createEdge(Edge::EDGE_CALL, callerNode, calleeNode);
addTokenLocation(edge, location);
}
void Storage::onFieldUsageParsed(const ParseLocation& location, const std::string& userName, const std::string& usedName)
{
log("usage", userName + " -> " + usedName, location);
Node* userNode = m_graph.createNodeHierarchy(userName);
Node* usedNode = m_graph.createNodeHierarchy(usedName);
Edge* edge = m_graph.createEdge(Edge::EDGE_USAGE, userNode, usedNode);
addTokenLocation(edge, location);
}
void Storage::onGlobalVariableUsageParsed(
const ParseLocation& location, const std::string& userName, const std::string& usedName
)
{
log("usage", userName + " -> " + usedName, location);
Node* userNode = m_graph.createNodeHierarchy(userName);
Node* usedNode = m_graph.createNodeHierarchy(usedName);
Edge* edge = m_graph.createEdge(Edge::EDGE_USAGE, userNode, usedNode);
addTokenLocation(edge, location);
}
Id Storage::getIdForNodeWithName(const std::string& fullName) const
{
Node* node = m_graph.getNode(fullName);
return (node ? node->getId() : 0);
}
std::string Storage::getNameForNodeWithId(Id id) const
{
Token* token = m_graph.getTokenById(id);
if (!token)
{
return "";
}
if (token->isEdge())
{
return dynamic_cast<Edge*>(token)->getName();
}
else
{
return dynamic_cast<Node*>(token)->getFullName();
}
}
std::vector<std::string> Storage::getNamesForNodesWithNamePrefix(const std::string& prefix) const
{
std::vector<std::string> names;
m_graph.forEachNode([&](Node* node){
const std::string& nodeName = node->getFullName();
if (utility::isPrefix(prefix, nodeName))
{
names.push_back(nodeName);
}
});
return names;
}
std::vector<Id> Storage::getIdsOfNeighbours(const Id id) const
{
std::vector<Id> result;
Node* node = m_graph.findNode([&](Node* node){
return node->getId() == id;
});
if (node != NULL)
{
std::map<Id, bool> addedIds;
addedIds[id] = true;
node->forEachEdge(
[&result, &addedIds](Edge* e)
{
Id fromId = e->getFrom()->getId();
if (addedIds.find(fromId) == addedIds.end())
{
result.push_back(fromId);
addedIds[fromId] = true;
}
Id toId = e->getTo()->getId();
if (addedIds.find(toId) == addedIds.end())
{
result.push_back(toId);
addedIds[toId] = true;
}
}
);
}
return result;
}
std::vector<std::tuple<Id, Id, Id>> Storage::getNeighbourEdgesOfNode(const Id id) const
{
std::vector<std::tuple<Id, Id, Id>> result;
Node* node = m_graph.findNode([&](Node* node){
return node->getId() == id;
});
if (node != NULL)
{
node->forEachEdge(
[&result](Edge* e)
{
result.push_back(std::tuple<Id, Id, Id>(e->getFrom()->getId(), e->getTo()->getId(), e->getId()));
}
);
}
return result;
}
std::vector<std::tuple<Id, Id, Id>> Storage::getMemberEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_MEMBER);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getUsageEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_USAGE);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getCallEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_CALL);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getTypeOfEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_TYPE_OF);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getReturnTypeOfEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_RETURN_TYPE_OF);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getParameterOfEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_PARAMETER_TYPE_OF);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getInheritanceEdgesOfNode(const Id id) const
{
return getEdgesOfTypeOfNode(id, Edge::EdgeType::EDGE_INHERITANCE);
}
std::pair<Id, Id> Storage::getNodesOfEdge(const Id id) const
{
std::pair<Id, Id> result;
Edge* edge = m_graph.findEdge([&](Edge* edge){
return edge->getId() == id;
});
if(edge != NULL)
{
result.first = edge->getFrom()->getId();
result.second = edge->getTo()->getId();
}
return result;
}
bool Storage::checkTokenIsNode(const Id id) const
{
Token* token = m_graph.findToken([&](Token* token){
return token->getId() == id;
});
if(token != NULL)
{
return token->isNode();
}
return false;
}
std::vector<Id> Storage::getActiveTokenIdsForId(Id tokenId) const
{
std::vector<Id> ret;
Token* token = m_graph.getTokenById(tokenId);
if (!token)
{
return ret;
}
Node* node;
if (token->isEdge())
{
node = dynamic_cast<Edge*>(token)->getTo();
}
else
{
node = dynamic_cast<Node*>(token);
}
ret.push_back(node->getId());
node->forEachEdge(
[&node, &ret](Edge* e)
{
if (e->getTo() == node)
{
ret.push_back(e->getId());
}
}
);
return ret;
}
std::vector<Id> Storage::getLocationIdsForTokenIds(const std::vector<Id>& tokenIds) const
{
std::vector<Id> ret;
for (Id tokenId : tokenIds)
{
Token* token = m_graph.getTokenById(tokenId);
if (!token)
{
continue;
}
ret.insert(ret.end(), token->getLocationIds().begin(), token->getLocationIds().end());
}
return ret;
}
TokenLocationCollection Storage::getTokenLocationsForLocationIds(const std::vector<Id>& locationIds) const
{
TokenLocationCollection ret;
for (Id locationId: locationIds)
{
TokenLocation* location = m_locationCollection.findTokenLocationById(locationId);
if (location->getOtherTokenLocation())
{
ret.addTokenLocationAsPlainCopy(location);
ret.addTokenLocationAsPlainCopy(location->getOtherTokenLocation());
}
}
return ret;
}
TokenLocationFile Storage::getTokenLocationsForFile(const std::string& filePath) const
{
TokenLocationFile ret(filePath);
TokenLocationFile* locationFile = m_locationCollection.findTokenLocationFileByPath(filePath);
if (!locationFile)
{
return ret;
}
locationFile->forEachTokenLocation(
[&](TokenLocation* tokenLocation) -> void
{
ret.addTokenLocationAsPlainCopy(tokenLocation);
}
);
return ret;
}
TokenLocationFile Storage::getTokenLocationsForLinesInFile(
const std::string& filePath, uint firstLineNumber, uint lastLineNumber
) const
{
TokenLocationFile ret(filePath);
TokenLocationFile* locationFile = m_locationCollection.findTokenLocationFileByPath(filePath);
if (!locationFile)
{
return ret;
}
for (uint i = firstLineNumber; i <= lastLineNumber; i++)
{
TokenLocationLine* locationLine = locationFile->findTokenLocationLineByNumber(i);
if (!locationLine)
{
continue;
}
locationLine->forEachTokenLocation(
[&](TokenLocation* tokenLocation) -> void
{
ret.addTokenLocationAsPlainCopy(tokenLocation);
}
);
}
return ret;
}
TokenComponentAccess::AccessType Storage::convertAccessType(ParserClient::AccessType access) const
{
switch (access)
{
case ACCESS_PUBLIC:
return TokenComponentAccess::ACCESS_PUBLIC;
case ACCESS_PROTECTED:
return TokenComponentAccess::ACCESS_PROTECTED;
case ACCESS_PRIVATE:
return TokenComponentAccess::ACCESS_PRIVATE;
case ACCESS_NONE:
return TokenComponentAccess::ACCESS_NONE;
}
}
TokenComponentAccess* Storage::addAccess(Node* node, ParserClient::AccessType access)
{
if (access != ACCESS_NONE)
{
std::shared_ptr<TokenComponentAccess> ptr = std::make_shared<TokenComponentAccess>(convertAccessType(access));
node->getMemberEdge()->addComponentAccess(ptr);
return ptr.get();
}
return nullptr;
}
Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const DataType& type)
{
Node* typeNode = m_graph.createNodeHierarchy(type.getRawTypeName());
Edge* edge = m_graph.createEdge(edgeType, node, typeNode);
// FIXME: When a function uses the same type multiple times then we still only use one edge to save this,
// but we can't store multiple DataTypes on this edge at the moment.
if (!edge->getComponent<TokenComponentDataType>())
{
edge->addComponentDataType(
std::make_shared<TokenComponentDataType>(type.getQualifierList(), type.getModifierStack())
);
}
return edge;
}
Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeUsage& typeUsage)
{
if (!typeUsage.location.isValid())
{
return nullptr;
}
Edge* edge = addTypeEdge(node, edgeType, typeUsage.dataType);
addTokenLocation(edge, typeUsage.location);
return edge;
}
TokenLocation* Storage::addTokenLocation(Token* token, const ParseLocation& loc)
{
if (!loc.isValid())
{
return nullptr;
}
TokenLocation* location = m_locationCollection.addTokenLocation(
token->getId(), loc.filePath,
loc.startLineNumber, loc.startColumnNumber,
loc.endLineNumber, loc.endColumnNumber
);
token->addLocationId(location->getId());
return location;
}
void Storage::log(std::string type, std::string str, const ParseLocation& location) const
{
LOG_INFO_STREAM(
<< type << ": " << str << " <" << location.filePath << " "
<< location.startLineNumber << ":" << location.startColumnNumber << " "
<< location.endLineNumber << ":" << location.endColumnNumber << ">"
);
}
std::vector<std::tuple<Id, Id, Id>> Storage::getEdgesOfTypeOfNode(const Id id, const Edge::EdgeType type) const
{
std::vector<std::tuple<Id, Id, Id>> result;
Node* node = m_graph.findNode([&](Node* node){
return node->getId() == id;
});
if (node != NULL)
{
node->forEachEdge(
[&result, &type](Edge* e)
{
if(e->getType() == type)
{
result.push_back(std::tuple<Id, Id, Id>(e->getFrom()->getId(), e->getTo()->getId(), e->getId()));
}
}
);
}
return result;
}