|
14 | 14 | #include "clang/AST/CXXInheritance.h" |
15 | 15 | #include "clang/AST/Decl.h" |
16 | 16 | #include "clang/AST/DeclCXX.h" |
| 17 | +#include "clang/AST/DeclTemplate.h" |
17 | 18 | #include "clang/AST/GlobalDecl.h" |
18 | 19 | #include "clang/AST/Mangle.h" |
19 | 20 | #include "clang/AST/QualTypeNames.h" |
|
42 | 43 | #include <set> |
43 | 44 | #include <sstream> |
44 | 45 | #include <string> |
| 46 | +#include <vector> |
45 | 47 |
|
46 | 48 | // Stream redirect. |
47 | 49 | #ifdef _WIN32 |
@@ -1026,11 +1028,103 @@ namespace Cpp { |
1026 | 1028 | funcs.push_back(Found); |
1027 | 1029 | } |
1028 | 1030 |
|
| 1031 | + namespace { |
| 1032 | + inline void |
| 1033 | + collectUniqueTemplateArgs(const std::vector<TemplateArgInfo>& templ_types, |
| 1034 | + std::vector<TemplateArgInfo>& result) { |
| 1035 | + std::unique_copy(templ_types.begin(), templ_types.end(), |
| 1036 | + std::back_inserter(result)); |
| 1037 | + } |
| 1038 | + bool |
| 1039 | + IsTemplateFunctionGoodMatch(const FunctionTemplateDecl* FTD, |
| 1040 | + const std::vector<TemplateArgInfo>& arg_types, |
| 1041 | + std::vector<TemplateArgInfo>& templ_types) { |
| 1042 | + const FunctionDecl* F = FTD->getTemplatedDecl(); |
| 1043 | + clang::TemplateParameterList* tpl = FTD->getTemplateParameters(); |
| 1044 | + |
| 1045 | + if (arg_types.size() != F->getNumParams()) |
| 1046 | + return false; |
| 1047 | + |
| 1048 | + for (size_t i = 0; i < arg_types.size(); i++) { |
| 1049 | + QualType fn_arg_type = F->getParamDecl(i)->getType(); |
| 1050 | + QualType arg_type = QualType::getFromOpaquePtr(arg_types[i].m_Type); |
| 1051 | + |
| 1052 | + // dereference |
| 1053 | + if (fn_arg_type->isReferenceType()) |
| 1054 | + fn_arg_type = fn_arg_type.getNonReferenceType(); |
| 1055 | + if (arg_type->isReferenceType()) |
| 1056 | + arg_type = arg_type.getNonReferenceType(); |
| 1057 | + |
| 1058 | + fn_arg_type = fn_arg_type.getCanonicalType(); |
| 1059 | + arg_type = arg_type.getCanonicalType(); |
| 1060 | + |
| 1061 | + // matching parameter and argument types |
| 1062 | + // resolving parameter |
| 1063 | + const auto* fn_TST = |
| 1064 | + fn_arg_type->getAs<clang::TemplateSpecializationType>(); |
| 1065 | + const TemplateDecl* fn_TD = nullptr; |
| 1066 | + if (fn_TST) |
| 1067 | + fn_TD = fn_TST->getTemplateName().getAsTemplateDecl(); |
| 1068 | + |
| 1069 | + // resolving argument |
| 1070 | + const auto* arg_RT = arg_type->getAs<clang::RecordType>(); |
| 1071 | + ClassTemplateSpecializationDecl* arg_CTSD = nullptr; |
| 1072 | + if (arg_RT) |
| 1073 | + arg_CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>( |
| 1074 | + arg_RT->getDecl()); |
| 1075 | + |
| 1076 | + if ((!arg_CTSD || !fn_TD) && (arg_CTSD || fn_TD)) |
| 1077 | + return false; |
| 1078 | + |
| 1079 | + // check if types match |
| 1080 | + if (arg_CTSD) { |
| 1081 | + auto* arg_D = arg_CTSD->getSpecializedTemplate()->getCanonicalDecl(); |
| 1082 | + if (arg_D != fn_TD->getCanonicalDecl()) |
| 1083 | + return false; |
| 1084 | + if (templ_types.size() < tpl->size()) { |
| 1085 | + Cpp::GetClassTemplateInstantiationArgs(arg_CTSD, templ_types); |
| 1086 | + break; |
| 1087 | + } |
| 1088 | + } else if (templ_types.size() < tpl->size()) { |
| 1089 | + templ_types.push_back(arg_types[i]); |
| 1090 | + } |
| 1091 | + } |
| 1092 | + return true; |
| 1093 | + } |
| 1094 | + } // namespace |
| 1095 | + |
1029 | 1096 | TCppFunction_t |
1030 | 1097 | BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates, |
1031 | 1098 | const std::vector<TemplateArgInfo>& explicit_types, |
1032 | 1099 | const std::vector<TemplateArgInfo>& arg_types) { |
1033 | 1100 |
|
| 1101 | + /* |
| 1102 | + Try matching function with templated class as arguments first |
| 1103 | + Example: |
| 1104 | +
|
| 1105 | + template<typename T> |
| 1106 | + struct A { T value; }; |
| 1107 | +
|
| 1108 | + template<typename T> |
| 1109 | + void somefunc(A<T> arg); // overload 1 |
| 1110 | +
|
| 1111 | + template<typename T> |
| 1112 | + void somefunc(T arg); // overload 2 |
| 1113 | +
|
| 1114 | + somefunc(A<int>()); // should call overload 1; resolve this first |
| 1115 | + somefunc(3); // should call overload 2 |
| 1116 | + */ |
| 1117 | + for (const auto& candidate : candidates) { |
| 1118 | + std::vector<TemplateArgInfo> templ_types; |
| 1119 | + auto* TFD = static_cast<FunctionTemplateDecl*>(candidate); |
| 1120 | + if (IsTemplateFunctionGoodMatch(TFD, arg_types, templ_types)) { |
| 1121 | + TCppFunction_t instantiated = InstantiateTemplate( |
| 1122 | + candidate, templ_types.data(), templ_types.size()); |
| 1123 | + if (instantiated) |
| 1124 | + return instantiated; |
| 1125 | + } |
| 1126 | + } |
| 1127 | + |
1034 | 1128 | for (const auto& candidate : candidates) { |
1035 | 1129 | auto* TFD = (FunctionTemplateDecl*)candidate; |
1036 | 1130 | clang::TemplateParameterList* tpl = TFD->getTemplateParameters(); |
@@ -1060,9 +1154,19 @@ namespace Cpp { |
1060 | 1154 | if (instantiated) |
1061 | 1155 | return instantiated; |
1062 | 1156 |
|
| 1157 | + std::vector<TemplateArgInfo> unique_arg_types; |
| 1158 | + collectUniqueTemplateArgs(arg_types, unique_arg_types); |
| 1159 | + instantiated = InstantiateTemplate(candidate, unique_arg_types.data(), |
| 1160 | + unique_arg_types.size()); |
| 1161 | + if (instantiated) |
| 1162 | + return instantiated; |
| 1163 | + |
1063 | 1164 | // Force the instantiation with template params in case of no args |
1064 | 1165 | // maybe steer instantiation better with arg set returned from |
1065 | 1166 | // TemplateProxy? |
| 1167 | + if (explicit_types.empty()) |
| 1168 | + continue; |
| 1169 | + |
1066 | 1170 | instantiated = InstantiateTemplate(candidate, explicit_types.data(), |
1067 | 1171 | explicit_types.size()); |
1068 | 1172 | if (instantiated) |
|
0 commit comments