From b7cbef3772b4cae357592b128d19f486f8601277 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Mon, 14 Jul 2014 16:21:10 +0200 Subject: [PATCH] data: saving locations of return and parameter types This change introduces the structure ParseTypeUsage for passing information about type usage from the parser to it's client. It is used for passing data type and location information about return types and parameter types, which now get saved to the corresponding edges in the Storage. --- src/lib/CMakeLists.txt | 4 +- src/lib/data/Storage.cpp | 58 ++++++++++++------ src/lib/data/Storage.h | 9 +-- src/lib/data/parser/ParseLocation.cpp | 5 ++ src/lib/data/parser/ParseLocation.h | 2 + src/lib/data/parser/ParseTypeUsage.cpp | 7 +++ src/lib/data/parser/ParseTypeUsage.h | 15 +++++ src/lib/data/parser/ParseVariable.cpp | 1 - src/lib/data/parser/ParserClient.cpp | 19 +++--- src/lib/data/parser/ParserClient.h | 17 +++--- src/lib/data/parser/cxx/ASTVisitor.cpp | 52 +++++++++++++--- src/lib/data/parser/cxx/ASTVisitor.h | 4 +- src/test/CxxParserTestSuite.h | 82 +++++++++++++++++++++++--- 13 files changed, 215 insertions(+), 60 deletions(-) create mode 100644 src/lib/data/parser/ParseTypeUsage.cpp create mode 100644 src/lib/data/parser/ParseTypeUsage.h diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 627a52af..7c7ced5d 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -69,7 +69,7 @@ add_files( data/graph/edgeComponent/EdgeComponent.h data/graph/edgeComponent/EdgeComponentDataType.cpp data/graph/edgeComponent/EdgeComponentDataType.h - + data/graph/Edge.cpp data/graph/Edge.h data/graph/Graph.cpp @@ -94,6 +94,8 @@ add_files( data/parser/Parser.h data/parser/ParserClient.cpp data/parser/ParserClient.h + data/parser/ParseTypeUsage.cpp + data/parser/ParseTypeUsage.h data/parser/ParseVariable.cpp data/parser/ParseVariable.h diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index d0cda02c..5906f22f 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -7,6 +7,7 @@ #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" @@ -105,30 +106,30 @@ void Storage::onFieldParsed(const ParseLocation& location, const ParseVariable& } void Storage::onFunctionParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters ) { log("function", fullName, location); Node* node = m_graph.createNodeHierarchyWithDistinctSignature( fullName, - ParserClient::functionSignatureStr(returnType, fullName, parameters, false) + ParserClient::functionSignatureStr(returnType.type, fullName, parameters, false) ); node->setType(Node::NODE_FUNCTION); - addTypeEdge(node, Edge::EDGE_RETURN_TYPE_OF, returnType); - for (const ParseVariable& parameter : parameters) - { - addTypeEdge(node, Edge::EDGE_PARAMETER_TYPE_OF, parameter.type); - } - 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 DataType& returnType, - const std::vector& parameters, AccessType access, AbstractionType abstraction, + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters, AccessType access, AbstractionType abstraction, bool isConst, bool isStatic ) { @@ -136,7 +137,7 @@ void Storage::onMethodParsed( Node* node = m_graph.createNodeHierarchyWithDistinctSignature( fullName, - ParserClient::functionSignatureStr(returnType, fullName, parameters, isConst) + ParserClient::functionSignatureStr(returnType.type, fullName, parameters, isConst) ); node->setType(Node::NODE_METHOD); @@ -150,13 +151,13 @@ void Storage::onMethodParsed( } node->setAccess(convertAccessType(access)); - addTypeEdge(node, Edge::EDGE_RETURN_TYPE_OF, returnType); - for (const ParseVariable& parameter : parameters) - { - addTypeEdge(node, Edge::EDGE_PARAMETER_TYPE_OF, parameter.type); - } - 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) @@ -381,8 +382,29 @@ Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const DataType& return edge; } +Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeUsage& typeUsage) +{ + if (!typeUsage.location.isValid()) + { + return nullptr; + } + + const DataType& type = typeUsage.type; + Node* typeNode = m_graph.createNodeHierarchy(type.getRawTypeName()); + Edge* edge = m_graph.createEdge(edgeType, node, typeNode); + edge->addComponent(std::make_shared(type.getQualifierList(), type.getModifierStack())); + + 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, diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 6d0bc95b..fefc8f7d 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -36,12 +36,12 @@ public: virtual void onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access); virtual void onFunctionParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters ); virtual void onMethodParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters, AccessType access, AbstractionType abstraction, + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters, AccessType access, AbstractionType abstraction, bool isConst, bool isStatic ); @@ -73,6 +73,7 @@ public: private: Edge::AccessType convertAccessType(ParserClient::AccessType access) const; Edge* addTypeEdge(Node* node, Edge::EdgeType edgeType, const DataType& type); + Edge* addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeUsage& typeUsage); TokenLocation* addTokenLocation(Token* token, const ParseLocation& location); void log(std::string type, std::string str, const ParseLocation& location) const; diff --git a/src/lib/data/parser/ParseLocation.cpp b/src/lib/data/parser/ParseLocation.cpp index e55cf65a..818bcf99 100644 --- a/src/lib/data/parser/ParseLocation.cpp +++ b/src/lib/data/parser/ParseLocation.cpp @@ -12,3 +12,8 @@ ParseLocation::ParseLocation( , endColumnNumber(endColumnNumber) { } + +bool ParseLocation::isValid() const +{ + return startLineNumber > 0 && endLineNumber >= startLineNumber; +} diff --git a/src/lib/data/parser/ParseLocation.h b/src/lib/data/parser/ParseLocation.h index 7c58832e..559db785 100644 --- a/src/lib/data/parser/ParseLocation.h +++ b/src/lib/data/parser/ParseLocation.h @@ -10,6 +10,8 @@ struct ParseLocation unsigned int startLineNumber, unsigned int startColumnNumber, unsigned int endLineNumber, unsigned int endColumnNumber); + bool isValid() const; + const std::string filePath; unsigned int startLineNumber; unsigned int startColumnNumber; diff --git a/src/lib/data/parser/ParseTypeUsage.cpp b/src/lib/data/parser/ParseTypeUsage.cpp new file mode 100644 index 00000000..16794c9f --- /dev/null +++ b/src/lib/data/parser/ParseTypeUsage.cpp @@ -0,0 +1,7 @@ +#include "data/parser/ParseTypeUsage.h" + +ParseTypeUsage::ParseTypeUsage(const ParseLocation& location, const DataType& type) + : location(location) + , type(type) +{ +} diff --git a/src/lib/data/parser/ParseTypeUsage.h b/src/lib/data/parser/ParseTypeUsage.h new file mode 100644 index 00000000..76c1f1d0 --- /dev/null +++ b/src/lib/data/parser/ParseTypeUsage.h @@ -0,0 +1,15 @@ +#ifndef PARSE_TYPE_USAGE_H +#define PARSE_TYPE_USAGE_H + +#include "data/type/DataType.h" +#include "data/parser/ParseLocation.h" + +struct ParseTypeUsage +{ + ParseTypeUsage(const ParseLocation& location, const DataType& type); + + const ParseLocation location; + const DataType type; +}; + +#endif // PARSE_TYPE_USAGE_H diff --git a/src/lib/data/parser/ParseVariable.cpp b/src/lib/data/parser/ParseVariable.cpp index fe6894b8..a0521030 100644 --- a/src/lib/data/parser/ParseVariable.cpp +++ b/src/lib/data/parser/ParseVariable.cpp @@ -1,6 +1,5 @@ #include "data/parser/ParseVariable.h" - ParseVariable::ParseVariable(const DataType& type, const std::string& fullName, bool isStatic) : type(type) , fullName(fullName) diff --git a/src/lib/data/parser/ParserClient.cpp b/src/lib/data/parser/ParserClient.cpp index bf0e89cc..d9be5d78 100644 --- a/src/lib/data/parser/ParserClient.cpp +++ b/src/lib/data/parser/ParserClient.cpp @@ -3,6 +3,7 @@ #include #include "data/parser/ParseLocation.h" +#include "data/parser/ParseTypeUsage.h" #include "data/parser/ParseVariable.h" #include "data/type/DataType.h" @@ -60,22 +61,18 @@ std::string ParserClient::addLocationSuffix(const std::string& str, const ParseL return ss.str(); } -std::string ParserClient::variableStr(const ParseVariable& variable, bool withName) +std::string ParserClient::variableStr(const ParseVariable& variable) { - std::string str = variable.type.getFullTypeName(); - if (withName) - { - str += " " + variable.fullName; - } + std::string str = variable.type.getFullTypeName() + " " + variable.fullName; return addStaticPrefix(str, variable.isStatic); } -std::string ParserClient::parameterStr(const std::vector parameters, bool withName) +std::string ParserClient::parameterStr(const std::vector parameters) { std::string str = "("; for (size_t i = 0; i < parameters.size(); i++) { - str += variableStr(parameters[i], withName); + str += parameters[i].type.getFullTypeName(); if (i < parameters.size() - 1) { str += ", "; @@ -87,7 +84,7 @@ std::string ParserClient::parameterStr(const std::vector paramete std::string ParserClient::functionStr( const DataType& returnType, const std::string& fullName, - const std::vector& parameters, + const std::vector& parameters, bool isConst ){ return addConstPrefix( @@ -100,10 +97,10 @@ std::string ParserClient::functionStr( std::string ParserClient::functionSignatureStr( const DataType& returnType, const std::string& fullName, - const std::vector& parameters, + const std::vector& parameters, bool isConst ){ - return addConstPrefix(fullName + parameterStr(parameters, false), isConst, false); + return addConstPrefix(fullName + parameterStr(parameters), isConst, false); } ParserClient::ParserClient() diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index c38692bd..871e91a3 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -5,6 +5,7 @@ #include struct ParseLocation; +struct ParseTypeUsage; struct ParseVariable; class DataType; @@ -29,18 +30,18 @@ public: static std::string addStaticPrefix(const std::string& str, bool isStatic); static std::string addConstPrefix(const std::string& str, bool isConst, bool atFront); static std::string addLocationSuffix(const std::string& str, const ParseLocation& location); - static std::string variableStr(const ParseVariable& variable, bool withName = true); - static std::string parameterStr(const std::vector parameters, bool withName = true); + static std::string variableStr(const ParseVariable& variable); + static std::string parameterStr(const std::vector parameters); static std::string functionStr( const DataType& returnType, const std::string& fullName, - const std::vector& parameters, + const std::vector& parameters, bool isConst ); static std::string functionSignatureStr( const DataType& returnType, const std::string& fullName, - const std::vector& parameters, + const std::vector& parameters, bool isConst ); @@ -57,11 +58,11 @@ public: virtual void onFieldParsed(const ParseLocation& location, const ParseVariable& variable, AccessType access) = 0; virtual void onFunctionParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters) = 0; + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters) = 0; virtual void onMethodParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters, AccessType access, AbstractionType abstraction, + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters, AccessType access, AbstractionType abstraction, bool isConst, bool isStatic) = 0; virtual void onNamespaceParsed(const ParseLocation& location, const std::string& fullName) = 0; diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index f6df2c13..4385c39b 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -3,6 +3,7 @@ #include "data/parser/cxx/ASTBodyVisitor.h" #include "data/parser/cxx/utilityCxx.h" #include "data/parser/ParseLocation.h" +#include "data/parser/ParseTypeUsage.h" #include "data/parser/ParseVariable.h" #include "data/type/DataType.h" @@ -139,7 +140,7 @@ bool ASTVisitor::VisitFunctionDecl(clang::FunctionDecl* declaration) m_client->onFunctionParsed( getParseLocation(declaration->getSourceRange()), declaration->getQualifiedNameAsString(), - utility::qualTypeToDataType(declaration->getReturnType()), + getParseTypeUsageOfReturnType(declaration), getParameters(declaration) ); @@ -170,7 +171,7 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration) m_client->onMethodParsed( getParseLocation(declaration->getSourceRange()), declaration->getQualifiedNameAsString(), - utility::qualTypeToDataType(declaration->getReturnType()), + getParseTypeUsageOfReturnType(declaration), getParameters(declaration), convertAccessType(declaration->getAccess()), abstraction, @@ -285,6 +286,11 @@ bool ASTVisitor::hasValidLocation(const clang::Decl* declaration) const ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange) const { + if (sourceRange.isInvalid()) + { + return ParseLocation("", 0, 0, 0, 0); + } + const clang::SourceManager& sourceManager = m_context->getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(sourceRange.getBegin()); @@ -299,10 +305,16 @@ ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange ); } +ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::ValueDecl* declaration) const +{ + return ParseTypeUsage( + getParseLocation(declaration->getSourceRange()), + utility::qualTypeToDataType(declaration->getType()) + ); +} + ParseVariable ASTVisitor::getParseVariable(clang::ValueDecl* declaration) const { - clang::QualType qualType = declaration->getType(); - bool isStatic = false; if (clang::isa(declaration)) { @@ -311,19 +323,43 @@ ParseVariable ASTVisitor::getParseVariable(clang::ValueDecl* declaration) const } return ParseVariable( - utility::qualTypeToDataType(qualType), + utility::qualTypeToDataType(declaration->getType()), declaration->getQualifiedNameAsString(), isStatic ); } -std::vector ASTVisitor::getParameters(clang::FunctionDecl* declaration) const +ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const { - std::vector parameters; + // TODO: use FunctionDecl::getReturnTypeSourceRange() in newer clang version + clang::SourceRange range; + const clang::TypeSourceInfo *TSI = declaration->getTypeSourceInfo(); + if (TSI) + { + clang::FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs(); + if (FTL) + { + // Skip self-referential return types. + range = clang::SourceRange( + FTL.getReturnLoc().getLocStart(), + declaration->getNameInfo().getLocStart().getLocWithOffset(-2) + ); + } + } + + return ParseTypeUsage( + getParseLocation(range), + utility::qualTypeToDataType(declaration->getReturnType()) + ); +} + +std::vector ASTVisitor::getParameters(clang::FunctionDecl* declaration) const +{ + std::vector parameters; for (unsigned i = 0; i < declaration->getNumParams(); i++) { - parameters.push_back(getParseVariable(declaration->getParamDecl(i))); + parameters.push_back(getParseTypeUsage(declaration->getParamDecl(i))); } return parameters; diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index 145922c1..04273dfe 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -45,8 +45,10 @@ public: private: bool hasValidLocation(const clang::Decl* declaration) const; ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; + ParseTypeUsage getParseTypeUsage(clang::ValueDecl* declaration) const; ParseVariable getParseVariable(clang::ValueDecl* declaration) const; - std::vector getParameters(clang::FunctionDecl* declaration) const; + ParseTypeUsage getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const; + std::vector getParameters(clang::FunctionDecl* declaration) const; DataType qualTypeToDataType(clang::QualType qualType); std::string getTypeName(const clang::QualType& qualType) const; ParserClient::AccessType convertAccessType(clang::AccessSpecifier) const; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index b6742ff4..df9f99ec 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -5,6 +5,7 @@ #include "data/parser/cxx/CxxParser.h" #include "data/parser/ParseLocation.h" #include "data/parser/ParserClient.h" +#include "data/parser/ParseTypeUsage.h" #include "data/parser/ParseVariable.h" #include "utility/text/TextAccess.h" @@ -197,7 +198,7 @@ public: ); TS_ASSERT_EQUALS(client->functions.size(), 1); - TS_ASSERT_EQUALS(client->functions[0], "int ceil(float a) <1:1 4:1>"); + TS_ASSERT_EQUALS(client->functions[0], "int ceil(float) <1:1 4:1>"); } void test_cxx_parser_finds_function_in_anonymous_namespace() @@ -210,7 +211,7 @@ public: ); 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>"); + TS_ASSERT_EQUALS(client->functions[0], "int (anonymous namespace)::sum(int, int) <3:2 3:22>"); } void test_cxx_parser_finds_method_declaration() @@ -674,6 +675,49 @@ public: TS_ASSERT_EQUALS(client->calls[1], "main -> App::operator+ <11:2 11:8>"); } + void test_cxx_parser_finds_return_type_use_in_function() + { + std::shared_ptr client = parseCode( + "double PI()\n" + "{\n" + " return 3.14159265359;\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 1); + TS_ASSERT_EQUALS(client->typeUses[0], "double <1:1 1:6>"); + } + + void test_cxx_parser_finds_return_and_parameter_type_uses_in_function() + { + std::shared_ptr client = parseCode( + "int ceil(float a)\n" + "{\n" + " return static_cast(a) + 1;\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 2); + TS_ASSERT_EQUALS(client->typeUses[0], "int <1:1 1:3>"); + TS_ASSERT_EQUALS(client->typeUses[1], "float <1:10 1:16>"); + } + + void test_cxx_parser_finds_parameter_type_uses_in_constructor() + { + std::shared_ptr client = parseCode( + "class A\n" + "{\n" + " A(int a, bool b, float c, int d);\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->typeUses.size(), 4); + TS_ASSERT_EQUALS(client->typeUses[0], "int <3:4 3:8>"); + TS_ASSERT_EQUALS(client->typeUses[1], "_Bool <3:11 3:16>"); + TS_ASSERT_EQUALS(client->typeUses[2], "float <3:19 3:25>"); + TS_ASSERT_EQUALS(client->typeUses[3], "int <3:28 3:32>"); + } + void test_cxx_parser_parses_multiple_files() { std::shared_ptr client = std::make_shared(); @@ -730,24 +774,36 @@ private: } virtual void onFunctionParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters ){ - std::string str = functionStr(returnType, fullName, parameters, false); + std::string str = functionStr(returnType.type, fullName, parameters, false); functions.push_back(addLocationSuffix(str, location)); + + addTypeUse(returnType); + for (const ParseTypeUsage& parameter : parameters) + { + addTypeUse(parameter); + } } virtual void onMethodParsed( - const ParseLocation& location, const std::string& fullName, const DataType& returnType, - const std::vector& parameters, AccessType access, AbstractionType abstraction, + const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& returnType, + const std::vector& parameters, AccessType access, AbstractionType abstraction, bool isConst, bool isStatic ) { - std::string str = functionStr(returnType, fullName, parameters, isConst); + std::string str = functionStr(returnType.type, fullName, parameters, isConst); str = addStaticPrefix(addAbstractionPrefix(str, abstraction), isStatic); str = addAccessPrefix(str, access); str = addLocationSuffix(str, location); methods.push_back(str); + + addTypeUse(returnType); + for (const ParseTypeUsage& parameter : parameters) + { + addTypeUse(parameter); + } } virtual void onNamespaceParsed(const ParseLocation& location, const std::string& fullName) @@ -790,6 +846,16 @@ private: std::vector structs; std::vector inheritances; std::vector calls; + std::vector typeUses; + + private: + void addTypeUse(const ParseTypeUsage& use) + { + if (use.location.isValid()) + { + typeUses.push_back(addLocationSuffix(use.type.getFullTypeName(), use.location)); + } + } }; std::shared_ptr parseCode(std::string code) const