data: Template Member Specialization Edge

* Added a new edge that connects a method of an implicitly specialized template class to its definition in the unspecialized template class.
* Added a test case for this.
* Made methods that have an invalid source location stored as undefined.
This commit is contained in:
malte_langkabel
2015-10-13 13:29:36 +02:00
parent 27bf5108ab
commit e61171cc85
8 changed files with 133 additions and 40 deletions
+19 -1
View File
@@ -317,7 +317,7 @@ Id Storage::onMethodParsed(
){
log("method", method.getFullName(), location);
Id nodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, method, true);
Id nodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, method, location.isValid() && scopeLocation.isValid());
addSourceLocation(nodeId, location);
addSourceLocation(nodeId, scopeLocation, true);
addAccess(nodeId, access);
@@ -621,6 +621,24 @@ Id Storage::onTemplateRecordSpecializationParsed(
return specializedNodeId;
}
Id Storage::onTemplateMemberFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction
){
log(
"template member function specialization",
instantiatedFunction.getFullName() + " -> " + specializedFunction.getFullName(),
location
);
Id instantiatedFunctionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, instantiatedFunction, false);
Id specializedFunctionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, specializedFunction, false);
Id edgeId = addEdge(instantiatedFunctionNodeId, specializedFunctionNodeId, Edge::EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF, location);
return edgeId;
}
Id Storage::onTemplateFunctionParameterTypeParsed(
const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function
){
+3
View File
@@ -109,6 +109,9 @@ public:
virtual Id onTemplateRecordSpecializationParsed(
const ParseLocation& location, const NameHierarchy& specializedRecordNameHierarchy,
const RecordType specializedRecordType, const NameHierarchy& specializedFromNameHierarchy);
virtual Id onTemplateMemberFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction);
virtual Id onTemplateFunctionParameterTypeParsed(
const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function);
virtual Id onTemplateFunctionSpecializationParsed(
+7 -3
View File
@@ -46,10 +46,12 @@ Edge::EdgeType Edge::intToType(int value)
case 0x2000:
return EDGE_TEMPLATE_SPECIALIZATION_OF;
case 0x4000:
return EDGE_INCLUDE;
return EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF;
case 0x8000:
return EDGE_AGGREGATION;
return EDGE_INCLUDE;
case 0x10000:
return EDGE_AGGREGATION;
case 0x20000:
return EDGE_MACRO_USAGE;
}
@@ -194,6 +196,8 @@ std::string Edge::getTypeString(EdgeType type)
return "template_default_argument";
case EDGE_TEMPLATE_SPECIALIZATION_OF:
return "template_specialization";
case EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF:
return "template_member_specialization";
case EDGE_INCLUDE:
return "include";
case EDGE_AGGREGATION:
@@ -236,7 +240,7 @@ std::ostream& operator<<(std::ostream& ostream, const Edge& edge)
return ostream;
}
bool Edge::checkType() const
bool Edge::checkType() const // TODO: remove this function
{
Node::NodeTypeMask complexTypeMask = Node::NODE_CLASS | Node::NODE_STRUCT | Node:: NODE_TEMPLATE_PARAMETER_TYPE;
Node::NodeTypeMask typeMask = Node::NODE_ENUM | Node::NODE_TYPEDEF | complexTypeMask;
+19 -18
View File
@@ -18,26 +18,27 @@ public:
typedef int EdgeTypeMask;
enum EdgeType : EdgeTypeMask
{
EDGE_NONE = 0x0,
EDGE_MEMBER = 0x1,
EDGE_TYPE_OF = 0x2,
EDGE_RETURN_TYPE_OF = 0x4, // unused: see Storage::addFunctionNode()
EDGE_PARAMETER_TYPE_OF = 0x8, // unused: see Storage::addFunctionNode()
EDGE_TYPE_USAGE = 0x10,
EDGE_USAGE = 0x20,
EDGE_CALL = 0x40,
EDGE_INHERITANCE = 0x80,
EDGE_OVERRIDE = 0x100,
EDGE_TYPEDEF_OF = 0x200,
EDGE_TEMPLATE_PARAMETER = 0x400,
EDGE_TEMPLATE_ARGUMENT = 0x800,
EDGE_TEMPLATE_DEFAULT_ARGUMENT = 0x1000,
EDGE_TEMPLATE_SPECIALIZATION_OF = 0x2000,
EDGE_NONE = 0x0,
EDGE_MEMBER = 0x1,
EDGE_TYPE_OF = 0x2,
EDGE_RETURN_TYPE_OF = 0x4, // unused: see Storage::addFunctionNode()
EDGE_PARAMETER_TYPE_OF = 0x8, // unused: see Storage::addFunctionNode()
EDGE_TYPE_USAGE = 0x10,
EDGE_USAGE = 0x20,
EDGE_CALL = 0x40,
EDGE_INHERITANCE = 0x80,
EDGE_OVERRIDE = 0x100,
EDGE_TYPEDEF_OF = 0x200,
EDGE_TEMPLATE_PARAMETER = 0x400,
EDGE_TEMPLATE_ARGUMENT = 0x800,
EDGE_TEMPLATE_DEFAULT_ARGUMENT = 0x1000,
EDGE_TEMPLATE_SPECIALIZATION_OF = 0x2000,
EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF = 0x4000,
EDGE_INCLUDE = 0x4000,
EDGE_INCLUDE = 0x8000,
EDGE_AGGREGATION = 0x8000,
EDGE_MACRO_USAGE = 0x10000,
EDGE_AGGREGATION = 0x10000,
EDGE_MACRO_USAGE = 0x20000,
};
static int typeToInt(EdgeType type);
+3
View File
@@ -127,6 +127,9 @@ public:
virtual Id onTemplateRecordSpecializationParsed(
const ParseLocation& location, const NameHierarchy& specializedRecordNameHierarchy,
const RecordType specializedRecordType, const NameHierarchy& specializedFromNameHierarchy) = 0;
virtual Id onTemplateMemberFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction) = 0;
virtual Id onTemplateFunctionParameterTypeParsed(
const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy,
const ParseFunction function) = 0;
+46 -12
View File
@@ -173,16 +173,6 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
{
if (isLocatedInUnparsedProjectFile(declaration))
{
ParserClient::AbstractionType abstraction = ParserClient::ABSTRACTION_NONE;
if (declaration->isPure())
{
abstraction = ParserClient::ABSTRACTION_PURE_VIRTUAL;
}
else if (declaration->isVirtual())
{
abstraction = ParserClient::ABSTRACTION_VIRTUAL;
}
ParseFunction parseFunction = getParseFunction(declaration);
ParseLocation location = getParseLocationForNamedDecl(declaration);
@@ -190,7 +180,7 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration)
location,
parseFunction,
convertAccessType(declaration->getAccess()),
abstraction,
getAbstractionType(declaration),
getParseLocationOfFunctionBody(declaration)
);
@@ -363,8 +353,9 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration)
specializationParentNameHierarchy
);
std::string specializationFilePath = specializationLocation.filePath.str();
// template arguments
std::string specializationFilePath = specializationLocation.filePath.str();
const clang::TemplateArgumentList &argList = specializationDecl->getTemplateArgs();
for (size_t i = 0; i < argList.size(); i++)
{
@@ -379,6 +370,35 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration)
);
}
}
// template methods
if (specializationDecl->getSpecializationKind() == clang::TSK_ImplicitInstantiation)
{
for (clang::CXXRecordDecl::method_iterator methodIt = specializationDecl->method_begin(); methodIt != specializationDecl->method_end(); methodIt++)
{
clang::CXXMethodDecl* methodDecl = (*methodIt);
if (methodDecl->getTemplatedKind() == clang::FunctionDecl::TK_MemberSpecialization)
{
m_client->onMethodParsed(
getParseLocation(methodDecl->getMemberSpecializationInfo()->getPointOfInstantiation()),
getParseFunction(methodDecl),
convertAccessType(methodDecl->getAccess()),
getAbstractionType(methodDecl),
ParseLocation()
);
clang::NamedDecl* specializedNamedDecel = methodDecl->getMemberSpecializationInfo()->getInstantiatedFrom();
if (clang::isa<clang::FunctionDecl>(specializedNamedDecel))
{
m_client->onTemplateMemberFunctionSpecializationParsed(
getParseLocation(methodDecl->getMemberSpecializationInfo()->getPointOfInstantiation()),
getParseFunction(methodDecl),
getParseFunction(clang::dyn_cast<clang::FunctionDecl>(specializedNamedDecel))
);
}
}
}
}
}
}
return true;
@@ -799,6 +819,20 @@ ParserClient::AccessType ASTVisitor::convertAccessType(clang::AccessSpecifier ac
}
}
ParserClient::AbstractionType ASTVisitor::getAbstractionType(const clang::CXXMethodDecl* methodDecl) const
{
ParserClient::AbstractionType abstraction = ParserClient::ABSTRACTION_NONE;
if (methodDecl->isPure())
{
abstraction = ParserClient::ABSTRACTION_PURE_VIRTUAL;
}
else if (methodDecl->isVirtual())
{
abstraction = ParserClient::ABSTRACTION_VIRTUAL;
}
return abstraction;
}
ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange) const
{
if (sourceRange.isInvalid())
+1
View File
@@ -64,6 +64,7 @@ private:
bool isLocatedInProjectFile(const clang::Decl* declaration) const;
ParserClient::AccessType convertAccessType(clang::AccessSpecifier) const;
ParserClient::AbstractionType getAbstractionType(const clang::CXXMethodDecl* methodDecl) const;
ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const;
ParseLocation getParseLocationForNamedDecl(const clang::NamedDecl* decl, const clang::SourceLocation& loc) const;
+35 -6
View File
@@ -1599,6 +1599,24 @@ public:
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<A>->A<typename T> <0:0 0:0>");
}
void test_cxx_parser_finds__of_implicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
"public:\n"
" T foo() {}\n"
"};\n"
"int main()\n"
"{\n"
" A<int> a;\n"
"}\n"
);
TS_ASSERT_EQUALS(client->templateMemberSpecializations.size(), 1);
TS_ASSERT_EQUALS(client->templateMemberSpecializations[0], "A<int>::foo -> A<typename T>::foo <0:0 0:0>");
}
void test_cxx_parser_finds_explicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -2492,11 +2510,11 @@ private:
{
}
virtual void prepareParsingFile()
virtual void prepareParsingFile(const FilePath& filePath)
{
}
virtual void finishParsingFile()
virtual void finishParsingFile(const FilePath& filePath)
{
}
@@ -2715,10 +2733,20 @@ private:
const ParseLocation& location, const NameHierarchy& specializedRecordNameHierarchy,
const RecordType specializedRecordType, const NameHierarchy& specializedFromNameHierarchy)
{
templateSpecializations.push_back(
addLocationSuffix(std::string(specializedRecordType == ParserClient::RECORD_CLASS ? "class" : "struct") + " " +
specializedRecordNameHierarchy.getFullName() + " -> " + specializedFromNameHierarchy.getFullName(), location)
);
templateSpecializations.push_back(addLocationSuffix(
std::string(specializedRecordType == ParserClient::RECORD_CLASS ? "class" : "struct") + " " +
specializedRecordNameHierarchy.getFullName() + " -> " + specializedFromNameHierarchy.getFullName(), location
));
return 0;
}
virtual Id onTemplateMemberFunctionSpecializationParsed(
const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction)
{
// needs to be implemented
templateMemberSpecializations.push_back(addLocationSuffix(
instantiatedFunction.getFullName() + " -> " + specializedFunction.getFullName(), location
));
return 0;
}
@@ -2791,6 +2819,7 @@ private:
std::vector<std::string> templateArgumentTypes;
std::vector<std::string> templateDefaultArgumentTypes;
std::vector<std::string> templateSpecializations;
std::vector<std::string> templateMemberSpecializations;
std::vector<std::string> files;
std::vector<std::string> includes;