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:
@@ -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
|
||||
){
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user