data: refined template parameter names
* Fixed template parameters to be resolved to their correct names even if they are (re)definied outside of the class (e.g. for template method definitions). * Added test code.
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
template <typename T>
|
||||
template <typename T, typename U>
|
||||
class TemplateTestClass
|
||||
{
|
||||
void run(T param);
|
||||
public:
|
||||
template <typename P>
|
||||
void run(P param);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void TemplateTestClass<T>::run(T param)
|
||||
template <typename T, typename U>
|
||||
template <typename P>
|
||||
void TemplateTestClass<T, U>::run(P param)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
TemplateTestClass<int> t2;
|
||||
TemplateTestClass<float, float> t1;
|
||||
t1.run<float>(6.9f);
|
||||
TemplateTestClass<int, int> t2;
|
||||
t2.run<int>(6);
|
||||
return 0;
|
||||
}
|
||||
@@ -534,13 +534,11 @@ Id Storage::onTemplateDefaultArgumentTypeParsed(
|
||||
}
|
||||
|
||||
Id Storage::onTemplateRecordParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName,
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy,
|
||||
const std::vector<std::string>& templateRecordNameHierarchy
|
||||
){
|
||||
log("template record type parameter", templateParameterTypeName, location);
|
||||
log("template record type parameter", utility::join(templateParameterTypeNameHierarchy, "::"), location);
|
||||
|
||||
std::vector<std::string> templateParameterTypeNameHierarchy = templateRecordNameHierarchy;
|
||||
templateParameterTypeNameHierarchy.back() += "::" + templateParameterTypeName;
|
||||
Node* templateParameterNode = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy);
|
||||
addTokenLocation(templateParameterNode, location);
|
||||
|
||||
@@ -576,12 +574,10 @@ Id Storage::onTemplateRecordSpecializationParsed(
|
||||
}
|
||||
|
||||
Id Storage::onTemplateFunctionParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy, const ParseFunction function
|
||||
){
|
||||
log("template function type parameter", templateParameterTypeName, location);
|
||||
log("template function type parameter", utility::join(templateParameterTypeNameHierarchy, "::"), location);
|
||||
|
||||
std::vector<std::string> templateParameterTypeNameHierarchy;
|
||||
templateParameterTypeNameHierarchy.push_back(function.getFullName() + "::"+ templateParameterTypeName);
|
||||
Node* templateParameterNode = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy);
|
||||
addTokenLocation(templateParameterNode, location);
|
||||
|
||||
|
||||
@@ -90,13 +90,13 @@ public:
|
||||
virtual Id onTemplateDefaultArgumentTypeParsed(
|
||||
const ParseTypeUsage& type, const std::vector<std::string>& templateArgumentTypeNameHierarchy);
|
||||
virtual Id onTemplateRecordParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName,
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy,
|
||||
const std::vector<std::string>& templateRecordNameHierarchy);
|
||||
virtual Id onTemplateRecordSpecializationParsed(
|
||||
const ParseLocation& location, const std::vector<std::string>& specializedRecordNameHierarchy,
|
||||
const RecordType specializedRecordType, const std::vector<std::string>& specializedFromNameHierarchy);
|
||||
virtual Id onTemplateFunctionParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function);
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy, const ParseFunction function);
|
||||
virtual Id onTemplateFunctionSpecializationParsed(
|
||||
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction);
|
||||
|
||||
|
||||
@@ -106,13 +106,13 @@ public:
|
||||
virtual Id onTemplateDefaultArgumentTypeParsed(
|
||||
const ParseTypeUsage& type, const std::vector<std::string>& templateArgumentTypeNameHierarchy) = 0;
|
||||
virtual Id onTemplateRecordParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName,
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy,
|
||||
const std::vector<std::string>& templateRecordNameHierarchy) = 0;
|
||||
virtual Id onTemplateRecordSpecializationParsed(
|
||||
const ParseLocation& location, const std::vector<std::string>& specializedRecordNameHierarchy,
|
||||
const RecordType specializedRecordType, const std::vector<std::string>& specializedFromNameHierarchy) = 0;
|
||||
virtual Id onTemplateFunctionParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName,
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy,
|
||||
const ParseFunction function) = 0;
|
||||
virtual Id onTemplateFunctionSpecializationParsed(
|
||||
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) = 0;
|
||||
|
||||
@@ -305,7 +305,7 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration)
|
||||
{
|
||||
m_client->onTemplateRecordParameterTypeParsed(
|
||||
getParseLocationForNamedDecl(namedDecl),
|
||||
namedDecl->getNameAsString(),
|
||||
utility::getDeclNameHierarchy(namedDecl),
|
||||
templateRecordNameHierarchy
|
||||
);
|
||||
}
|
||||
@@ -369,7 +369,7 @@ bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplat
|
||||
{
|
||||
m_client->onTemplateRecordParameterTypeParsed(
|
||||
getParseLocationForNamedDecl(namedDecl),
|
||||
namedDecl->getNameAsString(),
|
||||
utility::getDeclNameHierarchy(namedDecl),
|
||||
specializedRecordNameHierarchy
|
||||
);
|
||||
}
|
||||
@@ -402,11 +402,11 @@ bool ASTVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declarat
|
||||
|
||||
if (isLocatedInMainFile(namedDecl))
|
||||
{
|
||||
std::string templateParameterTypeName = namedDecl->getNameAsString();
|
||||
std::vector<std::string> templateParameterTypeNameHierarchy = utility::getDeclNameHierarchy(namedDecl);
|
||||
|
||||
m_client->onTemplateFunctionParameterTypeParsed(
|
||||
getParseLocationForNamedDecl(namedDecl),
|
||||
templateParameterTypeName,
|
||||
templateParameterTypeNameHierarchy,
|
||||
templateFunction
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,47 +6,47 @@
|
||||
#include "data/parser/cxx/ASTActionFactory.h"
|
||||
#include "data/parser/cxx/CxxDiagnosticConsumer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static std::vector<std::string> getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs, llvm::StringRef FileName)
|
||||
namespace
|
||||
{
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("clang-tool");
|
||||
Args.push_back("-fsyntax-only");
|
||||
Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
|
||||
Args.push_back(FileName.str());
|
||||
return Args;
|
||||
}
|
||||
|
||||
// custom implementation of clang::runToolOnCodeWithArgs which also sets our custon DiagnosticConsumer
|
||||
static bool runToolOnCodeWithArgs(
|
||||
clang::DiagnosticConsumer* DiagConsumer,
|
||||
clang::FrontendAction *ToolAction,
|
||||
const llvm::Twine &Code,
|
||||
const std::vector<std::string> &Args,
|
||||
const llvm::Twine &FileName = "input.cc",
|
||||
const clang::tooling::FileContentMappings &VirtualMappedFiles = clang::tooling::FileContentMappings()
|
||||
){
|
||||
llvm::SmallString<16> FileNameStorage;
|
||||
llvm::StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
|
||||
llvm::IntrusiveRefCntPtr<clang::FileManager> Files(new clang::FileManager(clang::FileSystemOptions()));
|
||||
clang::tooling::ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction, Files.get());
|
||||
|
||||
llvm::SmallString<1024> CodeStorage;
|
||||
Invocation.mapVirtualFile(FileNameRef,
|
||||
Code.toNullTerminatedStringRef(CodeStorage));
|
||||
|
||||
for (auto &FilenameWithContent : VirtualMappedFiles)
|
||||
static std::vector<std::string> getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs, llvm::StringRef FileName)
|
||||
{
|
||||
Invocation.mapVirtualFile(FilenameWithContent.first,
|
||||
FilenameWithContent.second);
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("clang-tool");
|
||||
Args.push_back("-fsyntax-only");
|
||||
Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
|
||||
Args.push_back(FileName.str());
|
||||
return Args;
|
||||
}
|
||||
|
||||
Invocation.setDiagnosticConsumer(DiagConsumer);
|
||||
// custom implementation of clang::runToolOnCodeWithArgs which also sets our custon DiagnosticConsumer
|
||||
static bool runToolOnCodeWithArgs(
|
||||
clang::DiagnosticConsumer* DiagConsumer,
|
||||
clang::FrontendAction *ToolAction,
|
||||
const llvm::Twine &Code,
|
||||
const std::vector<std::string> &Args,
|
||||
const llvm::Twine &FileName = "input.cc",
|
||||
const clang::tooling::FileContentMappings &VirtualMappedFiles = clang::tooling::FileContentMappings()
|
||||
)
|
||||
{
|
||||
llvm::SmallString<16> FileNameStorage;
|
||||
llvm::StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
|
||||
llvm::IntrusiveRefCntPtr<clang::FileManager> Files(new clang::FileManager(clang::FileSystemOptions()));
|
||||
clang::tooling::ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction, Files.get());
|
||||
|
||||
return Invocation.run();
|
||||
}
|
||||
llvm::SmallString<1024> CodeStorage;
|
||||
Invocation.mapVirtualFile(FileNameRef,
|
||||
Code.toNullTerminatedStringRef(CodeStorage));
|
||||
|
||||
for (auto &FilenameWithContent : VirtualMappedFiles)
|
||||
{
|
||||
Invocation.mapVirtualFile(FilenameWithContent.first,
|
||||
FilenameWithContent.second);
|
||||
}
|
||||
|
||||
Invocation.setDiagnosticConsumer(DiagConsumer);
|
||||
|
||||
return Invocation.run();
|
||||
}
|
||||
}
|
||||
|
||||
CxxParser::CxxParser(ParserClient* client, FileManager* fileManager)
|
||||
|
||||
@@ -105,17 +105,24 @@ namespace utility
|
||||
}
|
||||
case clang::Type::TemplateTypeParm:
|
||||
{
|
||||
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);
|
||||
|
||||
clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast<clang::TemplateTypeParmType>(qualType)->getDecl();
|
||||
typeNameHerarchy = getContextNameHierarchy(templateTypeParmDecl->getDeclContext());
|
||||
std::string typeName = getDeclName(templateTypeParmDecl);
|
||||
|
||||
clang::ASTContext& astContext = templateTypeParmDecl->getASTContext();
|
||||
llvm::ArrayRef<clang::ast_type_traits::DynTypedNode> parents = astContext.getParents<clang::Decl>(*(clang::dyn_cast<clang::Decl>(templateTypeParmDecl)));
|
||||
if (parents.size() > 0) // usually this list contains just one parent node.
|
||||
{
|
||||
const clang::Decl* parentNode = parents[0].get<clang::Decl>(); // use the fist parent node.
|
||||
if (clang::isa<clang::NamedDecl>(parentNode))
|
||||
{
|
||||
const clang::NamedDecl* parentNamedDecl = clang::dyn_cast<clang::NamedDecl>(parentNode);
|
||||
typeNameHerarchy = getDeclNameHierarchy(parentNamedDecl);
|
||||
}
|
||||
}
|
||||
if (typeNameHerarchy.size() == 0)
|
||||
{
|
||||
int gogo = 0;
|
||||
typeNameHerarchy.push_back(typeName); // HOT: fix this one! definition of template function outside of class scope!
|
||||
LOG_ERROR("Unable to resolve type name hierarchy for template parameter \"" + typeName + "\"");
|
||||
typeNameHerarchy.push_back(typeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -165,7 +172,7 @@ namespace utility
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("unhandled declaration type");
|
||||
LOG_ERROR("unhandled declaration type: " + std::string(declaration->getDeclKindName()));
|
||||
}
|
||||
contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext());
|
||||
if (clang::isa<clang::TemplateTypeParmDecl>(declaration))
|
||||
|
||||
@@ -1211,7 +1211,7 @@ public:
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<T>::T <1:20 1:20>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_template_parameter_type_of_template_class_with_multiple_parameters()
|
||||
void test_cxx_parser_finds_template_parameter_types_of_template_class_with_multiple_parameters()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T, typename U>\n"
|
||||
@@ -1225,6 +1225,26 @@ public:
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A<T, U>::U <1:32 1:32>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_template_parameter_of_template_method_definition_outside_template_class()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
" template <typename U>\n"
|
||||
" U foo();\n"
|
||||
"};\n"
|
||||
"template <typename T>\n"
|
||||
"template <typename U>\n"
|
||||
"U A<T>::foo()\n"
|
||||
"{}\n"
|
||||
);
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 3);
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<T>::T <1:20 1:20>");
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A<T>::foo<U>::U <4:21 4:21>");
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[2], "A<T>::foo<U>::U <8:20 8:20>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_template_argument_of_implicit_template_specialization()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
@@ -1895,11 +1915,11 @@ private:
|
||||
}
|
||||
|
||||
virtual Id onTemplateRecordParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName,
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy,
|
||||
const std::vector<std::string>& templateRecordNameHierarchy)
|
||||
{
|
||||
templateParameterTypes.push_back(
|
||||
addLocationSuffix(utility::join(templateRecordNameHierarchy, "::") + "::" + templateParameterTypeName, location)
|
||||
addLocationSuffix(utility::join(templateParameterTypeNameHierarchy, "::"), location)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
@@ -1916,11 +1936,11 @@ private:
|
||||
}
|
||||
|
||||
virtual Id onTemplateFunctionParameterTypeParsed(
|
||||
const ParseLocation& location, const std::string& templateParameterTypeName,
|
||||
const ParseLocation& location, const std::vector<std::string>& templateParameterTypeNameHierarchy,
|
||||
const ParseFunction function)
|
||||
{
|
||||
templateParameterTypes.push_back(
|
||||
addLocationSuffix(function.getFullName() + "::" + templateParameterTypeName, location)
|
||||
addLocationSuffix(utility::join(templateParameterTypeNameHierarchy, "::"), location)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user