From 63407c2c81a2fb1ec8772b346781a76563709001 Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Mon, 24 Nov 2014 16:50:31 +0100 Subject: [PATCH] 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. --- bin/app/data/src/header.h | 13 +- bin/test/data/log/test_log.txt | 38 +- src/app/qt/view/graphElements/QtGraphNode.cpp | 1 + src/lib/CMakeLists.txt | 2 - src/lib/data/Storage.cpp | 94 ++++- src/lib/data/Storage.h | 13 +- src/lib/data/graph/Edge.cpp | 23 +- src/lib/data/graph/Edge.h | 21 +- src/lib/data/graph/Node.cpp | 2 + src/lib/data/graph/Node.h | 28 +- .../graph/filter/GraphFilterImplementations.h | 14 +- .../TokenComponentDataType.cpp | 35 -- .../token_component/TokenComponentDataType.h | 29 -- src/lib/data/parser/ParserClient.h | 17 + src/lib/data/parser/cxx/ASTVisitor.cpp | 140 ++++++- src/lib/data/parser/cxx/ASTVisitor.h | 14 +- src/lib/data/parser/cxx/CxxParser.cpp | 8 +- src/lib/data/parser/cxx/utilityCxx.cpp | 129 ++++++- src/lib/data/parser/cxx/utilityCxx.h | 7 + src/lib/data/type/DataType.cpp | 24 +- src/lib/data/type/DataType.h | 10 +- src/test/CxxParserTestSuite.h | 349 +++++++++++++++++- src/test/DataTypeTestSuite.h | 18 +- src/test/StorageTestSuite.h | 2 +- 24 files changed, 792 insertions(+), 239 deletions(-) delete mode 100644 src/lib/data/graph/token_component/TokenComponentDataType.cpp delete mode 100644 src/lib/data/graph/token_component/TokenComponentDataType.h diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index 2e3c4545..0f82665e 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -132,15 +132,4 @@ public: private: int m_importantInt; -}; - -class AnotherClass - : public A -{ -public: - int publicInt; -protected: - int protectedInt; -private: - int privateInt; -}; +}; \ No newline at end of file diff --git a/bin/test/data/log/test_log.txt b/bin/test/data/log/test_log.txt index 3e822d83..bc9d566a 100644 --- a/bin/test/data/log/test_log.txt +++ b/bin/test/data/log/test_log.txt @@ -1,22 +1,4 @@ ConfigManager.cpp ERROR: value path/to/nowhere is not present in config. -Token.cpp ERROR: Location Id was not referenced by this Token. -Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class -Edge.cpp ERROR: Nodes are not plain copies. -Storage.cpp INFO: class: A -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::getCount -Storage.cpp INFO: global usage: A::getCount -> A::count -Storage.cpp INFO: method: A::process -Storage.cpp INFO: field: A::count -Storage.cpp INFO: class: B -Storage.cpp INFO: inheritance: B : A -Storage.cpp INFO: method: B::process -Storage.cpp INFO: type usage: B::process -> int -Storage.cpp INFO: function: main -Storage.cpp INFO: type usage: main -> B -Storage.cpp INFO: call: main -> B::B -Storage.cpp INFO: call: main -> A::getCount Storage.cpp INFO: class: A Storage.cpp INFO: method: A::A Storage.cpp INFO: global usage: A::A -> A::count @@ -49,6 +31,24 @@ SearchMatch.cpp INFO: 237 A::A ^^^^ +Storage.cpp INFO: class: A +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::getCount +Storage.cpp INFO: global usage: A::getCount -> A::count +Storage.cpp INFO: method: A::process +Storage.cpp INFO: field: A::count +Storage.cpp INFO: class: B +Storage.cpp INFO: inheritance: B : A +Storage.cpp INFO: method: B::process +Storage.cpp INFO: type usage: B::process -> int +Storage.cpp INFO: function: main +Storage.cpp INFO: type usage: main -> B +Storage.cpp INFO: call: main -> B::B +Storage.cpp INFO: call: main -> A::getCount +Token.cpp ERROR: Location Id was not referenced by this Token. +Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class +Edge.cpp ERROR: Nodes are not plain copies. Settings.cpp WARNING: File for Settings not found. ConfigManager.cpp ERROR: value Bool is not present in config. ConfigManager.cpp ERROR: value Int is not present in config. @@ -64,6 +64,7 @@ ConfigManager.cpp ERROR: value Int is not present in config. ConfigManager.cpp ERROR: value Float is not present in config. ConfigManager.cpp ERROR: value String is not present in config. ConfigManager.cpp ERROR: value NewBool is not present in config. +Graph.cpp ERROR: Can't remove member edge, without removing the child node. Storage.cpp INFO: typedef: type -> int Storage.cpp INFO: class: Class Storage.cpp INFO: struct: Struct @@ -103,7 +104,6 @@ Storage.cpp INFO: global usage: isTrue -> global Storage.cpp INFO: function: isTrue Storage.cpp INFO: struct: Struct Storage.cpp INFO: type usage: isTrue -> Struct -Graph.cpp ERROR: Can't remove member edge, without removing the child node. TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 diff --git a/src/app/qt/view/graphElements/QtGraphNode.cpp b/src/app/qt/view/graphElements/QtGraphNode.cpp index f423257a..60baa7f6 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.cpp +++ b/src/app/qt/view/graphElements/QtGraphNode.cpp @@ -283,6 +283,7 @@ void QtGraphNode::setStyle() case Node::NODE_CLASS: case Node::NODE_ENUM: case Node::NODE_TYPEDEF: + case Node::NODE_TEMPLATE_PARAMETER_TYPE: if (m_isHovering) { m_rect->setShadow(QColor(0, 0, 0, 255), 5); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 0148438e..e48cd8e3 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -89,8 +89,6 @@ add_files( data/graph/token_component/TokenComponentAccess.h data/graph/token_component/TokenComponentConst.cpp data/graph/token_component/TokenComponentConst.h - data/graph/token_component/TokenComponentDataType.cpp - data/graph/token_component/TokenComponentDataType.h data/graph/token_component/TokenComponentName.cpp data/graph/token_component/TokenComponentName.h data/graph/token_component/TokenComponentSignature.cpp diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 95e994fe..bebef18e 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -5,7 +5,6 @@ #include "data/graph/filter/GraphFilterConductor.h" #include "data/graph/token_component/TokenComponentConst.h" -#include "data/graph/token_component/TokenComponentDataType.h" #include "data/graph/token_component/TokenComponentName.h" #include "data/graph/token_component/TokenComponentStatic.h" #include "data/graph/SubGraph.h" @@ -323,6 +322,77 @@ Id Storage::onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& f return edge->getId(); } +Id Storage::onTemplateRecordParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, + const std::vector& templateRecordNameHierarchy +) +{ + log("class template type parameter", templateParameterTypeName, location); + std::vector templateParameterTypeNameHierarchy = templateRecordNameHierarchy; + templateParameterTypeNameHierarchy.back() += "::" + templateParameterTypeName; + Node* templateParameterNode = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy); + addTokenLocation(templateParameterNode, location); + + Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); + + Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_PARAMETER_OF, templateParameterNode, templateRecordNode); + //addTokenLocation(edge, location); + + + return 0; +} + +Id Storage::onTemplateRecordSpecializationParsed( + const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, + const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy) +{ + log("class template specialization", utility::join(specializedRecordNameHierarchy, "::") + " -> " + utility::join(templateRecordNameHierarchy, "::"), location); + + Node::NodeType specializedRecordNodeType = Node::NODE_CLASS; + if (specializedRecordType == ParserClient::RECORD_STRUCT) + { + specializedRecordNodeType = Node::NODE_STRUCT; + } + + Node* specializedRecordNode = addNodeHierarchy(specializedRecordNodeType, specializedRecordNameHierarchy); + Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); + Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_SPECIALIZATION_OF, specializedRecordNode, templateRecordNode); + //addTokenLocation(edge, location); + + return 0; +} + +Id Storage::onTemplateFunctionParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function +) +{ + log("function template type parameter", templateParameterTypeName, location); + + std::vector templateParameterTypeNameHierarchy; + templateParameterTypeNameHierarchy.push_back(function.getFullName() + "::"+ templateParameterTypeName); + Node* templateParameterNode = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy); + addTokenLocation(templateParameterNode, location); + + Node* templateFunctionNode = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, function); + + Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_PARAMETER_OF, templateParameterNode, templateFunctionNode); + + return 0; +} + +Id Storage::onTemplateFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction +) +{ + log("function template specialization", specializedFunction.getFullName(), location); + + Node* specializedFunctionNode = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, specializedFunction); + Node* templateFunctionNode = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, templateFunction); + Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_SPECIALIZATION_OF, specializedFunctionNode, templateFunctionNode); + + return 0; +} + Id Storage::getIdForNodeWithName(const std::string& fullName) const { SearchNode* node = m_tokenIndex.getNode(fullName); @@ -685,23 +755,6 @@ TokenComponentAbstraction* Storage::addAbstraction(Node* node, ParserClient::Abs return nullptr; } -Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const DataType& type) -{ - Node* typeNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, utility::splitToVector(type.getRawTypeName(), "::")); // TODO: do we really need to split here? - 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()) - { - edge->addComponentDataType( - std::make_shared(type.getQualifierList(), type.getModifierStack()) - ); - } - - return edge; -} - Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeUsage& typeUsage) { if (!typeUsage.location.isValid()) @@ -709,9 +762,10 @@ Edge* Storage::addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeU return nullptr; } - Edge* edge = addTypeEdge(node, edgeType, typeUsage.dataType); - + Node* typeNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, typeUsage.dataType.getTypeNameHierarchy()); + Edge* edge = m_graph.createEdge(edgeType, node, typeNode); addTokenLocation(edge, typeUsage.location); + return edge; } diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index bca8a46a..bf27490a 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -68,6 +68,17 @@ public: const ParseLocation& location, const ParseFunction& user, const std::vector& usedNameHierarchy); virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function); + virtual Id onTemplateRecordParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, + const std::vector& templateRecordNameHierarchy); + virtual Id onTemplateRecordSpecializationParsed( + const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, + const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy); + virtual Id onTemplateFunctionParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function); + virtual Id onTemplateFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction); + // GraphAccess implementation virtual Id getIdForNodeWithName(const std::string& fullName) const; virtual std::string getNameForNodeWithId(Id id) const; @@ -96,7 +107,6 @@ protected: private: Node* addNodeHierarchy(Node::NodeType type, std::vector nameHierarchy); - Node* addNodeHierarchy(Node::NodeType type, const std::string& fullName); Node* addNodeHierarchyWithDistinctSignature(Node::NodeType type, const ParseFunction& function); TokenComponentAccess::AccessType convertAccessType(ParserClient::AccessType access) const; @@ -105,7 +115,6 @@ private: TokenComponentAbstraction::AbstractionType convertAbstractionType(ParserClient::AbstractionType abstraction) const; TokenComponentAbstraction* addAbstraction(Node* node, ParserClient::AbstractionType abstraction); - 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, bool isScope = false); diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 7075efd9..d8f66d76 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -4,7 +4,6 @@ #include "data/graph/Node.h" #include "data/graph/token_component/TokenComponentAccess.h" -#include "data/graph/token_component/TokenComponentDataType.h" #include "utility/logging/logging.h" Edge::Edge(EdgeType type, Node* from, Node* to) @@ -93,24 +92,6 @@ void Edge::addComponentAccess(std::shared_ptr component) } } -void Edge::addComponentDataType(std::shared_ptr component) -{ - if (getComponent()) - { - LOG_ERROR("TokenComponentDataType has been set before!"); - } - else if (m_type != EDGE_TYPEDEF_OF && m_type != EDGE_TYPE_OF && - m_type != EDGE_RETURN_TYPE_OF && m_type != EDGE_PARAMETER_TYPE_OF && - m_type != EDGE_TYPE_USAGE) - { - LOG_ERROR("TokenComponentDataType can't be set on edge of type: " + getTypeString()); - } - else - { - addComponent(component); - } -} - std::string Edge::getTypeString(EdgeType type) const { switch (type) @@ -133,6 +114,10 @@ std::string Edge::getTypeString(EdgeType type) const return "usage"; case EDGE_TYPEDEF_OF: return "typedef"; + case EDGE_TEMPLATE_PARAMETER_OF: + return "template parameter"; + case EDGE_TEMPLATE_SPECIALIZATION_OF: + return "template specialization"; } return ""; } diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index 46df1009..34883d4a 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -16,15 +16,17 @@ public: typedef int EdgeTypeMask; enum EdgeType : EdgeTypeMask { - EDGE_MEMBER = 0x1, - EDGE_TYPE_OF = 0x2, - EDGE_RETURN_TYPE_OF = 0x4, - EDGE_PARAMETER_TYPE_OF = 0x8, - EDGE_TYPE_USAGE = 0x10, - EDGE_USAGE = 0x20, - EDGE_CALL = 0x40, - EDGE_INHERITANCE = 0x80, - EDGE_TYPEDEF_OF = 0x100 + EDGE_MEMBER = 0x1, + EDGE_TYPE_OF = 0x2, + EDGE_RETURN_TYPE_OF = 0x4, + EDGE_PARAMETER_TYPE_OF = 0x8, + EDGE_TYPE_USAGE = 0x10, + EDGE_USAGE = 0x20, + EDGE_CALL = 0x40, + EDGE_INHERITANCE = 0x80, + EDGE_TYPEDEF_OF = 0x100, + EDGE_TEMPLATE_PARAMETER_OF = 0x200, + EDGE_TEMPLATE_SPECIALIZATION_OF = 0x400 }; Edge(EdgeType type, Node* from, Node* to); @@ -45,7 +47,6 @@ public: // Component setters void addComponentAccess(std::shared_ptr component); - void addComponentDataType(std::shared_ptr component); // Logging. std::string getTypeString(EdgeType type) const; diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index 9ca37efb..a10fec85 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -313,6 +313,8 @@ std::string Node::getTypeString(NodeType type) const return "enum"; case NODE_TYPEDEF: return "typedef"; + case NODE_TEMPLATE_PARAMETER_TYPE: + return "template parameter type"; } return ""; } diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index a3d7e382..3e44f0e9 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -19,21 +19,23 @@ class Node: public Token { public: typedef int NodeTypeMask; + // list undefined types first to ensure that they get replaced by their defined counterparts when it is parsed. enum NodeType : NodeTypeMask { - NODE_UNDEFINED = 0x1, - NODE_UNDEFINED_FUNCTION = 0x2, - NODE_UNDEFINED_VARIABLE = 0x4, - NODE_UNDEFINED_TYPE = 0x8, - NODE_STRUCT = 0x10, - NODE_CLASS = 0x20, - NODE_GLOBAL_VARIABLE = 0x40, - NODE_FIELD = 0x80, - NODE_FUNCTION = 0x100, - NODE_METHOD = 0x200, - NODE_NAMESPACE = 0x400, - NODE_ENUM = 0x800, - NODE_TYPEDEF = 0x1000 + NODE_UNDEFINED = 0x1, + NODE_UNDEFINED_FUNCTION = 0x2, + NODE_UNDEFINED_VARIABLE = 0x4, + NODE_UNDEFINED_TYPE = 0x8, + NODE_STRUCT = 0x10, + NODE_CLASS = 0x20, + NODE_GLOBAL_VARIABLE = 0x40, + NODE_FIELD = 0x80, + NODE_FUNCTION = 0x100, + NODE_METHOD = 0x200, + NODE_NAMESPACE = 0x400, + NODE_ENUM = 0x800, + NODE_TYPEDEF = 0x1000, + NODE_TEMPLATE_PARAMETER_TYPE = 0x2000 }; Node(NodeType type, const std::string& name); diff --git a/src/lib/data/graph/filter/GraphFilterImplementations.h b/src/lib/data/graph/filter/GraphFilterImplementations.h index 2b5e3156..b10c6742 100644 --- a/src/lib/data/graph/filter/GraphFilterImplementations.h +++ b/src/lib/data/graph/filter/GraphFilterImplementations.h @@ -10,7 +10,6 @@ #include "data/graph/token_component/TokenComponentAbstraction.h" #include "data/graph/token_component/TokenComponentAccess.h" #include "data/graph/token_component/TokenComponentConst.h" -#include "data/graph/token_component/TokenComponentDataType.h" #include "data/graph/token_component/TokenComponentStatic.h" /* @@ -87,18 +86,7 @@ protected: { addNode(node); } - - Edge* edge = node->findEdgeOfType(Edge::EDGE_TYPE_OF); - if (!edge) - { - return; - } - - TokenComponentDataType* type = edge->getComponent(); - if (type && type->isConstQualified()) - { - addNode(node); - } + // TODO: add const component to field and variable nodes.. } }; diff --git a/src/lib/data/graph/token_component/TokenComponentDataType.cpp b/src/lib/data/graph/token_component/TokenComponentDataType.cpp deleted file mode 100644 index addfc457..00000000 --- a/src/lib/data/graph/token_component/TokenComponentDataType.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "data/graph/token_component/TokenComponentDataType.h" - -#include "data/type/DataType.h" - -TokenComponentDataType::TokenComponentDataType( - const DataTypeQualifierList qualifierList, const DataTypeModifierStack modifierStack -) - : m_qualifierList(qualifierList) - , m_modifierStack(modifierStack) -{ -} - -TokenComponentDataType::~TokenComponentDataType() -{ -} - -std::shared_ptr TokenComponentDataType::copy() const -{ - return std::make_shared(*this); -} - -DataType TokenComponentDataType::getDataType(const std::string& typeName) const -{ - return DataType(typeName, m_qualifierList, m_modifierStack); -} - -std::string TokenComponentDataType::getQualifiedTypeName(const std::string& typeName) const -{ - return m_modifierStack.applyTo(m_qualifierList.applyTo(typeName)); -} - -bool TokenComponentDataType::isConstQualified() const -{ - return m_qualifierList.hasQualifier(DataTypeQualifierList::QUALIFIER_CONST); -} diff --git a/src/lib/data/graph/token_component/TokenComponentDataType.h b/src/lib/data/graph/token_component/TokenComponentDataType.h deleted file mode 100644 index fc142714..00000000 --- a/src/lib/data/graph/token_component/TokenComponentDataType.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TOKEN_COMPONENT_DATA_TYPE_H -#define TOKEN_COMPONENT_DATA_TYPE_H - -#include "data/graph/token_component/TokenComponent.h" -#include "data/type/DataTypeModifierStack.h" -#include "data/type/DataTypeQualifierList.h" - -class DataType; - -class TokenComponentDataType - : public TokenComponent -{ -public: - TokenComponentDataType(const DataTypeQualifierList qualifierList, const DataTypeModifierStack modifierStack); - virtual ~TokenComponentDataType(); - - virtual std::shared_ptr copy() const; - - DataType getDataType(const std::string& typeName) const; - std::string getQualifiedTypeName(const std::string& typeName) const; - - bool isConstQualified() const; - -private: - const DataTypeQualifierList m_qualifierList; - const DataTypeModifierStack m_modifierStack; -}; - -#endif // TOKEN_COMPONENT_DATA_TYPE_H diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 01ade2e8..466dcae5 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -28,6 +28,11 @@ public: ABSTRACTION_NONE }; + enum RecordType { + RECORD_STRUCT, + RECORD_CLASS + }; + static std::string addAccessPrefix(const std::string& str, AccessType access); static std::string addAbstractionPrefix(const std::string& str, AbstractionType abstraction); static std::string addStaticPrefix(const std::string& str, bool isStatic); @@ -84,6 +89,18 @@ public: virtual Id onGlobalVariableUsageParsed( const ParseLocation& location, const ParseFunction& user, const std::vector& usedNameHierarchy) = 0; virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function) = 0; + + virtual Id onTemplateRecordParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, + const std::vector& templateRecordNameHierarchy) = 0; + virtual Id onTemplateRecordSpecializationParsed( + const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, + const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy) = 0; + virtual Id onTemplateFunctionParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, + const ParseFunction function) = 0; + virtual Id onTemplateFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) = 0; }; #endif // PARSER_CLIENT_H diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 71805d39..30ae5d87 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -9,6 +9,7 @@ #include "data/parser/ParseTypeUsage.h" #include "data/parser/ParseVariable.h" #include "data/type/DataType.h" +#include "utility/logging/logging.h" #include "utility/utilityString.h" ASTVisitor::ASTVisitor(clang::ASTContext* context, ParserClient* client) @@ -32,7 +33,7 @@ bool ASTVisitor::VisitTypedefDecl(clang::TypedefDecl* declaration) { m_client->onTypedefParsed( getParseLocationForNamedDecl(declaration), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + utility::getDeclNameHierarchy(declaration), getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getUnderlyingType()), convertAccessType(declaration->getAccess()) ); @@ -49,19 +50,19 @@ bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration) { m_client->onClassParsed( getParseLocationForNamedDecl(declaration), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + utility::getDeclNameHierarchy(declaration), convertAccessType(declaration->getAccess()), getParseLocationOfRecordBody(declaration) ); if (declaration->hasDefinition() && declaration->getNumBases()) { - for (const auto& it : declaration->bases()) + for (const clang::CXXBaseSpecifier& it : declaration->bases()) { m_client->onInheritanceParsed( getParseLocation(it.getSourceRange()), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), - utility::splitToVector(getTypeName(it.getType()), "::"), + utility::getDeclNameHierarchy(declaration), + utility::qualTypeToDataType(it.getType()).getTypeNameHierarchy(), convertAccessType(it.getAccessSpecifier()) ); } @@ -71,10 +72,11 @@ bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration) { m_client->onStructParsed( getParseLocationForNamedDecl(declaration), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + utility::getDeclNameHierarchy(declaration), convertAccessType(declaration->getAccess()), getParseLocationOfRecordBody(declaration) ); + // TODO: what about struct inheritance? } } @@ -181,7 +183,7 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration) getParseLocationOfFunctionBody(declaration) ); - if (declaration->hasBody() && declaration->isThisDeclarationADefinition()) + if (declaration->hasBody() && declaration->getBody() != NULL && declaration->isThisDeclarationADefinition()) { ASTBodyVisitor bodyVisitor(this, declaration); bodyVisitor.Visit(declaration->getBody()); @@ -206,7 +208,7 @@ bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration) m_client->onFieldUsageParsed( getParseLocationForNamedDecl(init->getMember(), init->getMemberLocation()), getParseFunction(declaration), - utility::splitToVector(init->getMember()->getQualifiedNameAsString(), "::") + utility::getDeclNameHierarchy(init->getMember()) ); } else if (init->isBaseInitializer()) @@ -222,7 +224,6 @@ bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration) } } } - return true; } @@ -232,11 +233,10 @@ bool ASTVisitor::VisitNamespaceDecl(clang::NamespaceDecl* declaration) { m_client->onNamespaceParsed( declaration->isAnonymousNamespace() ? ParseLocation() : getParseLocationForNamedDecl(declaration), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + utility::getDeclNameHierarchy(declaration), getParseLocation(declaration->getSourceRange()) ); } - return true; } @@ -246,12 +246,11 @@ bool ASTVisitor::VisitEnumDecl(clang::EnumDecl* declaration) { m_client->onEnumParsed( getParseLocationForNamedDecl(declaration), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + utility::getDeclNameHierarchy(declaration), convertAccessType(declaration->getAccess()), getParseLocation(declaration->getSourceRange()) ); } - return true; } @@ -261,13 +260,110 @@ bool ASTVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* declaration) { m_client->onEnumFieldParsed( getParseLocation(declaration->getSourceRange()), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::") + utility::getDeclNameHierarchy(declaration) ); } return true; } +bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) +{ + std::vector templateRecordNameHierarchy = utility::getDeclNameHierarchy(declaration); + + clang::TemplateParameterList* parameterList = declaration->getTemplateParameters(); + for (int i = 0; i < parameterList->size(); i++) + { + clang::NamedDecl* namedDecl = parameterList->getParam(i); + + if (hasValidLocation(namedDecl)) + { + std::string templateParameterTypeName = namedDecl->getNameAsString(); + + m_client->onTemplateRecordParameterTypeParsed( + getParseLocationForNamedDecl(namedDecl), + templateParameterTypeName, + templateRecordNameHierarchy + ); + } + } + + for (clang::ClassTemplateDecl::spec_iterator it = declaration->specializations().begin(); // template argument as parameter does not work + it != declaration->specializations().end(); it++ + ) + { + ParserClient::RecordType specializedRecordType = it->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; + std::vector specializedRecordNameHierarchy = utility::getDeclNameHierarchy(*(it)); + m_client->onTemplateRecordSpecializationParsed( + getParseLocationForNamedDecl(*it), specializedRecordNameHierarchy, specializedRecordType, templateRecordNameHierarchy + ); + } + return true; +} + +bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* declaration) +{ + //std::vector templateRecordNameHierarchy = utility::splitToVector( + // declaration->getQualifiedNameAsString(), "::" + //); + + //clang::ClassTemplateDecl* baseTemplateDecl = declaration->getSpecializedTemplate(); + + //std::string specializedParameterNamePart = "<"; + //const clang::TemplateArgumentList& templateArgumentList = declaration->getTemplateArgs(); + //for (int i = 0; i < templateArgumentList.size(); i++) + //{ + // DataType datatype = utility::qualTypeToDataType(templateArgumentList.get(i).getAsType()); + // if (datatype.isTemplateParameterType()) + // { + // specializedParameterNamePart += baseTemplateDecl->getTemplateParameters()->getParam(i)->getNameAsString(); + // } + // else + // { + // specializedParameterNamePart += datatype.getFullTypeName(); + // } + // specializedParameterNamePart += (i < templateArgumentList.size() - 1) ? ", " : ""; + //} + //specializedParameterNamePart += ">"; + + //int foo = 0; + + return true; +} + +bool ASTVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declaration) +{ + const ParseFunction templateFunction = getParseFunction(declaration->getTemplatedDecl()); + for (clang::FunctionTemplateDecl::spec_iterator it = declaration->specializations().begin(); it != declaration->specializations().end(); it++) + { + ParseLocation specializedFunctionLocation = getParseLocationForNamedDecl(*(it)); + ParseFunction specializedFunction = getParseFunction(*(it)); + m_client->onTemplateFunctionSpecializationParsed( + specializedFunctionLocation, + specializedFunction, + templateFunction); + + m_client->onFunctionParsed(specializedFunctionLocation, specializedFunction, getParseLocationOfFunctionBody(*(it))); + } + clang::TemplateParameterList* parameterList = declaration->getTemplateParameters(); + for (int i = 0; i < parameterList->size(); i++) + { + clang::NamedDecl* namedDecl = parameterList->getParam(i); + + if (hasValidLocation(namedDecl)) + { + std::string templateParameterTypeName = namedDecl->getNameAsString(); + + m_client->onTemplateFunctionParameterTypeParsed( + getParseLocationForNamedDecl(namedDecl), + templateParameterTypeName, + templateFunction + ); + } + } + return true; +} + void ASTVisitor::VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr) { // if (clang::FunctionDecl *CalleeDecl = CE->getDirectCallee()) @@ -340,7 +436,7 @@ void ASTVisitor::VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::Mem m_client->onFieldUsageParsed( parseLocation, getParseFunction(decl), - utility::splitToVector(expr->getMemberDecl()->getQualifiedNameAsString(), "::") + utility::getDeclNameHierarchy(expr->getMemberDecl()) ); } @@ -354,7 +450,7 @@ void ASTVisitor::VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::De m_client->onGlobalVariableUsageParsed( parseLocation, getParseFunction(decl), - utility::splitToVector(expr->getDecl()->getQualifiedNameAsString(), "::") + utility::getDeclNameHierarchy(expr->getDecl()) ); } @@ -504,16 +600,21 @@ std::vector ASTVisitor::getParameters(clang::FunctionDecl* decla ParseVariable ASTVisitor::getParseVariable(clang::DeclaratorDecl* declaration) const { - bool isStatic = false; + bool isStatic; + std::vector hameHierarchy = utility::getDeclNameHierarchy(declaration); if (clang::isa(declaration)) { clang::VarDecl* varDecl = clang::dyn_cast(declaration); isStatic = varDecl->isStaticDataMember() || varDecl->getStorageClass() == clang::SC_Static; } + else if (clang::isa(declaration)) + { + isStatic = false; // fieldDecls cannot be static. If they are, they are treated as VarDecls + } return ParseVariable( getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getType()), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + hameHierarchy, isStatic ); } @@ -522,6 +623,7 @@ ParseFunction ASTVisitor::getParseFunction(clang::FunctionDecl* declaration) con { bool isStatic = false; bool isConst = false; + if (clang::isa(declaration)) { clang::CXXMethodDecl* methodDecl = clang::dyn_cast(declaration); @@ -535,7 +637,7 @@ ParseFunction ASTVisitor::getParseFunction(clang::FunctionDecl* declaration) con return ParseFunction( getParseTypeUsageOfReturnType(declaration), - utility::splitToVector(declaration->getQualifiedNameAsString(), "::"), + utility::getDeclNameHierarchy(declaration), getParameters(declaration), isStatic, isConst diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index 2e3fe692..6df46e41 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -16,11 +16,11 @@ public: virtual ~ASTVisitor(); // Left for debugging purposes. Uncomment to see a colored ast-dump of the parsed file. - // virtual bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl) - // { - // decl->dump(); - // return true; - // } + //virtual bool VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl) + //{ + // decl->dump(); + // return true; + //} // RecursiveASTVisitor implementation virtual bool VisitStmt(const clang::Stmt* statement); // avoid visiting @@ -36,6 +36,10 @@ public: virtual bool VisitEnumDecl(clang::EnumDecl* declaration); // enums virtual bool VisitEnumConstantDecl(clang::EnumConstantDecl* declaration); // enum fields + virtual bool VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration); + virtual bool VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* declaration); + virtual bool VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declaration); + // ASTBodyVisitorClient implementation virtual void VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr); // calls virtual void VisitCallExprInDeclBody(clang::VarDecl* decl, clang::CallExpr* expr); // calls in initialization of global variables diff --git a/src/lib/data/parser/cxx/CxxParser.cpp b/src/lib/data/parser/cxx/CxxParser.cpp index 1f62d2b0..4726a0e7 100644 --- a/src/lib/data/parser/cxx/CxxParser.cpp +++ b/src/lib/data/parser/cxx/CxxParser.cpp @@ -26,6 +26,10 @@ void CxxParser::parseFiles( // verbose // args.push_back("-v"); + // The option -fno-delayed-template-parsing signals that templates that there should + // be AST elements for unused template functions as well. + args.push_back("-fno-delayed-template-parsing"); + // The option -c signals that no executable is built. args.push_back("-c"); @@ -72,5 +76,7 @@ void CxxParser::parseFiles( void CxxParser::parseFile(std::shared_ptr textAccess) { ASTActionFactory actionFactory(m_client); - clang::tooling::runToolOnCode(actionFactory.create(), textAccess->getText()); + std::vector args; + args.push_back("-fno-delayed-template-parsing"); + clang::tooling::runToolOnCodeWithArgs(actionFactory.create(), textAccess->getText(), args); } diff --git a/src/lib/data/parser/cxx/utilityCxx.cpp b/src/lib/data/parser/cxx/utilityCxx.cpp index 589a354d..9e24d24c 100644 --- a/src/lib/data/parser/cxx/utilityCxx.cpp +++ b/src/lib/data/parser/cxx/utilityCxx.cpp @@ -1,5 +1,9 @@ #include "data/parser/cxx/utilityCxx.h" +#include +#include +#include + #include "data/type/DataType.h" #include "data/type/modifier/DataTypeModifierArray.h" #include "data/type/modifier/DataTypeModifierPointer.h" @@ -7,12 +11,13 @@ #include "data/type/DataTypeModifierStack.h" #include "data/type/DataTypeQualifierList.h" #include "utility/utilityString.h" +#include "utility/logging/logging.h" namespace utility { DataType qualTypeToDataType(clang::QualType qualType) { - std::string typeName; + std::vector typeNameHerarchy; DataTypeQualifierList qualifierList; DataTypeModifierStack modifierStack; @@ -21,7 +26,7 @@ namespace utility const clang::Type* type = qualType.getTypePtr(); if (type->getAs()) { - typeName = utility::substrAfter(qualType.getAsString(), ' '); + typeNameHerarchy.push_back(utility::substrAfter(qualType.getAsString(), ' ')); break; } else if (type->isPointerType()) @@ -54,17 +59,35 @@ namespace utility qualType = type->getPointeeType(); } - else if (type->isStructureOrClassType() || type->isEnumeralType()) - { - // we are working on the string here to not lose the namespace information stored in the name. - typeName = utility::substrAfter(qualType.getAsString(), ' '); - - // typeName = qualType.getBaseTypeIdentifier()->getName(); // this one does not keep namespace information. - break; - } else { - typeName = qualType.getUnqualifiedType().getAsString(); + const clang::Type* type = qualType.getUnqualifiedType().getTypePtr(); + + if (clang::isa(type)) + { + typeNameHerarchy = getDeclNameHierarchy(clang::dyn_cast(type)->getDecl()); + } + else + { + clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions()); + pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A" + pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool" + std::string typeName = qualType.getUnqualifiedType().getAsString(pp); + + if (type->isTemplateTypeParmType()) + { + clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast(qualType.getUnqualifiedType())->getDecl(); + if (templateTypeParmDecl) + { + typeNameHerarchy = getContextNameHierarchy(templateTypeParmDecl->getDeclContext()); + typeNameHerarchy.back() += "::" + typeName; + } + } + else + { + typeNameHerarchy.push_back(typeName); + } + } break; } } @@ -73,12 +96,90 @@ namespace utility { qualifierList.addQualifier(DataTypeQualifierList::QUALIFIER_CONST); } + return DataType(typeNameHerarchy, qualifierList, modifierStack); + } - if (typeName == "_Bool") + std::vector getDeclNameHierarchy(clang::Decl* declaration) + { + std::string declName = ""; + + if (clang::isa(declaration)) { - typeName = "bool"; + declName = getDeclName(clang::dyn_cast(declaration)); + } + else + { + LOG_ERROR("unhandled declaration type"); + } + std::vector contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext()); + contextNameHierarchy.push_back(declName); + return contextNameHierarchy; + } + + std::vector getContextNameHierarchy(clang::DeclContext* declContext) + { + std::vector contextNameHierarchy; + + clang::DeclContext* parentContext = declContext->getParent(); + if (parentContext) + { + contextNameHierarchy = getContextNameHierarchy(parentContext); } - return DataType(typeName, qualifierList, modifierStack); + if (clang::isa(declContext)) + { + std::string declName = getDeclName(clang::dyn_cast(declContext)); + if (declName != "") + { + contextNameHierarchy.push_back(declName); + } + } + return contextNameHierarchy; + } + + std::string getDeclName(clang::NamedDecl* declaration) + { + std::string declName = declaration->getNameAsString(); + + if (clang::isa(declaration)) + { + clang::ClassTemplateDecl* templateClassDeclaration = clang::dyn_cast(declaration)->getDescribedClassTemplate(); + if (templateClassDeclaration) + { + declName = getDeclName(templateClassDeclaration); + } + else if (clang::isa(declaration)) + { + std::string specializedParameterNamePart = "<"; + const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast(declaration)->getTemplateArgs(); + for (int i = 0; i < templateArgumentList.size(); i++) + { + DataType datatype = utility::qualTypeToDataType(templateArgumentList.get(i).getAsType()); + specializedParameterNamePart += datatype.getFullTypeName(); + specializedParameterNamePart += (i < templateArgumentList.size() - 1) ? ", " : ""; + } + specializedParameterNamePart += ">"; + declName += specializedParameterNamePart; + } + } + else if (clang::isa(declaration)) + { + std::string templateParameterNamePart = "<"; + clang::TemplateParameterList* parameterList = clang::dyn_cast(declaration)->getTemplateParameters(); + for (int i = 0; i < parameterList->size(); i++) + { + clang::NamedDecl* namedDecl = parameterList->getParam(i); + + templateParameterNamePart += namedDecl->getNameAsString(); + templateParameterNamePart += (i < parameterList->size() - 1) ? ", " : ""; + } + templateParameterNamePart += ">"; + declName += templateParameterNamePart; + } + else if (clang::isa(declaration) && clang::dyn_cast(declaration)->isAnonymousNamespace()) + { + declName = "(anonymous namespace)"; + } + return declName; } } diff --git a/src/lib/data/parser/cxx/utilityCxx.h b/src/lib/data/parser/cxx/utilityCxx.h index bfa62a89..2220c642 100644 --- a/src/lib/data/parser/cxx/utilityCxx.h +++ b/src/lib/data/parser/cxx/utilityCxx.h @@ -2,14 +2,21 @@ #define UTILITY_CLANG_H #include +#include +#include #include "clang/AST/Type.h" +#include "clang/AST/Decl.h" class DataType; namespace utility { DataType qualTypeToDataType(clang::QualType qualType); + + std::vector getDeclNameHierarchy(clang::Decl* declaration); + std::vector getContextNameHierarchy(clang::DeclContext* declaration); + std::string getDeclName(clang::NamedDecl* declaration); } #endif // UTILITY_CLANG_H diff --git a/src/lib/data/type/DataType.cpp b/src/lib/data/type/DataType.cpp index c7109d90..8345b3c4 100644 --- a/src/lib/data/type/DataType.cpp +++ b/src/lib/data/type/DataType.cpp @@ -1,20 +1,23 @@ #include "data/type/DataType.h" -DataType::DataType(const std::string& typeName) - : m_typeName(typeName) +#include "utility/utilityString.h" + +DataType::DataType(const std::vector& typeNameHierarchy) + : m_typeNameHierarchy(typeNameHierarchy) { } -DataType::DataType(const std::string& typeName, const DataTypeQualifierList& qualifierList) - : m_typeName(typeName) +DataType::DataType(const std::vector& typeNameHierarchy, const DataTypeQualifierList& qualifierList) + : m_typeNameHierarchy(typeNameHierarchy) , m_qualifierList(qualifierList) { } DataType::DataType( - const std::string& typeName, const DataTypeQualifierList& qualifierList, const DataTypeModifierStack& modifierStack + const std::vector& typeNameHierarchy, const DataTypeQualifierList& qualifierList, + const DataTypeModifierStack& modifierStack ) - : m_typeName(typeName) + : m_typeNameHierarchy(typeNameHierarchy) , m_qualifierList(qualifierList) , m_modifierStack(modifierStack) { @@ -36,10 +39,15 @@ DataTypeModifierStack DataType::getModifierStack() const std::string DataType::getFullTypeName() const { - return m_modifierStack.applyTo(m_qualifierList.applyTo(m_typeName)); + return m_modifierStack.applyTo(m_qualifierList.applyTo(getRawTypeName())); } std::string DataType::getRawTypeName() const { - return m_typeName; + return utility::join(m_typeNameHierarchy, "::"); +} + +std::vector DataType::getTypeNameHierarchy() const +{ + return m_typeNameHierarchy; } diff --git a/src/lib/data/type/DataType.h b/src/lib/data/type/DataType.h index 31933537..e12b35d4 100644 --- a/src/lib/data/type/DataType.h +++ b/src/lib/data/type/DataType.h @@ -10,10 +10,11 @@ class DataType { public: - DataType(const std::string& typeName); - DataType(const std::string& typeName, const DataTypeQualifierList& qualifierList); + DataType(const std::vector& typeNameHierarchy); + DataType(const std::vector& typeNameHierarchy, const DataTypeQualifierList& qualifierList); DataType( - const std::string& typeName, const DataTypeQualifierList& qualifierList, const DataTypeModifierStack& modifierStack + const std::vector& typeNameHierarchy, const DataTypeQualifierList& qualifierList, + const DataTypeModifierStack& modifierStack ); ~DataType(); @@ -22,9 +23,10 @@ public: std::string getFullTypeName() const; std::string getRawTypeName() const; + std::vector getTypeNameHierarchy() const; private: - const std::string m_typeName; + const std::vector m_typeNameHierarchy; const DataTypeQualifierList m_qualifierList; const DataTypeModifierStack m_modifierStack; }; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 9655fc45..ba535b6f 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -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 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 client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <1:20 1:20>"); + } + + void test_cxx_parser_finds_template_parameter_type_of_template_class_with_multiple_parameters() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <1:20 1:20>"); + TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A::U <1:32 1:32>"); + } + + void test_cxx_parser_finds_correct_field_member_name_of_template_class_in_declaration() + { + std::shared_ptr client = parseCode( + "template \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::foo <4:6 4:8>"); + } + + void test_cxx_parser_finds_correct_field_member_type_of_template_class_in_declaration() + { + std::shared_ptr client = parseCode( + "template \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 A::foo <4:4 4:6>"); + } + + void test_cxx_parser_finds_template_class_specialization_with_non_template_argument() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " T foo;\n" + "};\n" + "\n" + "A a\n" + ); + + TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <2:7 2:7>"); + } + + void test_cxx_parser_finds_class_inheritance_from_specialized_template_class() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " T foo;\n" + "};\n" + "\n" + "class B: public A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->inheritances.size(), 1); + TS_ASSERT_EQUALS(client->inheritances[0], "B : public A <7:10 7:22>"); + } + + //void _____test_cxx_parser_finds_template_class_specialization_with_template_argument() + //{ + // std::shared_ptr client = parseCode( + // "template \n" + // "class A\n" + // "{\n" + // " T foo;\n" + // "};\n" + // "\n" + // "template \n" + // "class B: public A\n" + // "{\n" + // "};\n" + // ); + + // TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); + // TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <2:7 2:7>"); + //} + + void test_cxx_parser_finds_template_class_constructor_usage_of_field() + { + std::shared_ptr client = parseCode( + "template \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::A() -> A::foo <4:7 4:9>"); + } + + void test_cxx_parser_finds_enum_definition_in_template_class() + { + std::shared_ptr client = parseCode( + "template \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::TestType <4:2 <4:7 4:14> 8:2>"); + } + + void test_cxx_parser_finds_enum_usage_in_template_class() + { + std::shared_ptr client = parseCode( + "template \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::TestType A::foo <9:11 9:13>"); + } + + void test_cxx_parser_finds_enum_fields_in_template_class() + { + std::shared_ptr client = parseCode( + "template \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::TestType::TEST_ONE <6:3 6:3>"); + TS_ASSERT_EQUALS(client->enumFields[1], "A::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 client = parseCode( + // "template \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 A::B::foo <4:4 4:6>"); + //} + + void test_cxx_parser_finds_correct_method_member_name_of_template_class_in_declaration() + { + std::shared_ptr client = parseCode( + "template \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::foo() <4:6 4:8>"); + } + + void test_cxx_parser_finds_correct_method_member_return_type_of_template_class_in_declaration() + { + std::shared_ptr client = parseCode( + "template \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 A::foo() <4:4 4:6>"); + } + + void test_cxx_parser_finds_template_parameter_type_of_template_function() + { + std::shared_ptr client = parseCode( + "template \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 client = parseCode( + "template \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 client = parseCode( + "template \n" + "T test(T a)\n" + "{\n" + " return a;\n" + "};\n" + "\n" + "template <>\n" + "int test(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& templateRecordNameHierarchy) + { + templateParameterTypes.push_back( + addLocationSuffix(utility::join(templateRecordNameHierarchy, "::") + "::" + templateParameterTypeName, location) + ); + return 0; + } + + virtual Id onTemplateRecordSpecializationParsed( + const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, + const RecordType specializedRecordType, const std::vector& 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 typedefs; std::vector classes; std::vector enums; @@ -1150,8 +1489,10 @@ private: std::vector inheritances; std::vector calls; - std::vector usages; - std::vector typeUses; + std::vector usages; // for variables + std::vector typeUses; // for types + std::vector templateParameterTypes; + std::vector templateSpecializations; private: void addTypeUse(const ParseTypeUsage& use) diff --git a/src/test/DataTypeTestSuite.h b/src/test/DataTypeTestSuite.h index 5b30aedc..953e6c34 100644 --- a/src/test/DataTypeTestSuite.h +++ b/src/test/DataTypeTestSuite.h @@ -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()); - 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()); - 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()); - 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 modifier = std::make_shared(); 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()); modifierStack.push(std::make_shared()); - DataType dataType("int", qualifierList, modifierStack); + DataType dataType(utility::splitToVector("int", "::"), qualifierList, modifierStack); TS_ASSERT_EQUALS("int * *", dataType.getFullTypeName()); } }; diff --git a/src/test/StorageTestSuite.h b/src/test/StorageTestSuite.h index 2c4498ef..219b42f2 100644 --- a/src/test/StorageTestSuite.h +++ b/src/test/StorageTestSuite.h @@ -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 parameters(const std::string& param) const