mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 07:35:08 +00:00
Index std::make_unique and similar functions as constructor calls.
This commit is contained in:
parent
e7de24764e
commit
96894ae996
173
src/indexer.cc
173
src/indexer.cc
@ -12,6 +12,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
|
||||
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
|
||||
// |Foobar| in DISALLOW_COPY(Foobar)
|
||||
@ -20,6 +21,15 @@ namespace {
|
||||
|
||||
const bool kIndexStdDeclarations = true;
|
||||
|
||||
std::vector<std::string> BuildTypeDesc(clang::Cursor cursor) {
|
||||
std::vector<std::string> type_desc;
|
||||
for (clang::Cursor arg : cursor.get_arguments()) {
|
||||
if (arg.get_kind() == CXCursor_ParmDecl)
|
||||
type_desc.push_back(arg.get_type_description());
|
||||
}
|
||||
return type_desc;
|
||||
}
|
||||
|
||||
void AddFuncRef(std::vector<IndexFuncRef>* result, IndexFuncRef ref) {
|
||||
if (!result->empty() && (*result)[result->size() - 1] == ref)
|
||||
return;
|
||||
@ -89,6 +99,103 @@ struct NamespaceHelper {
|
||||
}
|
||||
};
|
||||
|
||||
// Caches all instances of constructors, regardless if they are indexed or not.
|
||||
// The constructor may have a make_unique call associated with it that we need
|
||||
// to export. If we do not capture the parameter type description for the
|
||||
// constructor we will not be able to attribute the constructor call correctly.
|
||||
struct ConstructorCache {
|
||||
using Usr = std::string;
|
||||
struct Constructor {
|
||||
std::vector<std::string> param_type_desc;
|
||||
Usr usr;
|
||||
};
|
||||
std::unordered_map<Usr, std::vector<Constructor>> constructors_;
|
||||
|
||||
// This should be called whenever there is a constructor declaration.
|
||||
void NotifyConstructor(clang::Cursor ctor_cursor) {
|
||||
Constructor ctor;
|
||||
ctor.usr = ctor_cursor.get_usr();
|
||||
ctor.param_type_desc = BuildTypeDesc(ctor_cursor);
|
||||
|
||||
// Insert into |constructors_|.
|
||||
std::string type_usr = ctor_cursor.get_semantic_parent().get_usr();
|
||||
auto existing_ctors = constructors_.find(type_usr);
|
||||
if (existing_ctors != constructors_.end()) {
|
||||
existing_ctors->second.push_back(ctor);
|
||||
} else {
|
||||
constructors_[type_usr] = {ctor};
|
||||
}
|
||||
}
|
||||
|
||||
// Tries to lookup a constructor in |type_usr| that takes arguments most
|
||||
// closely aligned to |param_type_desc|.
|
||||
optional<std::string> TryFindConstructorUsr(
|
||||
const std::string& type_usr,
|
||||
const std::vector<std::string>& param_type_desc) {
|
||||
auto count_matching_prefix_length = [](const char* a, const char* b) {
|
||||
int matched = 0;
|
||||
while (*a && *b) {
|
||||
if (*a != *b)
|
||||
break;
|
||||
++a;
|
||||
++b;
|
||||
++matched;
|
||||
}
|
||||
// Additional score if the strings were the same length, which makes
|
||||
// "a"/"a" match higher than "a"/"a&"
|
||||
if (*a == *b)
|
||||
matched += 1;
|
||||
return matched;
|
||||
};
|
||||
|
||||
// Try to find constructors for the type. If there are no constructors
|
||||
// available, return an empty result.
|
||||
auto ctors_it = constructors_.find(type_usr);
|
||||
if (ctors_it == constructors_.end())
|
||||
return nullopt;
|
||||
const std::vector<Constructor>& ctors = ctors_it->second;
|
||||
if (ctors.empty())
|
||||
return nullopt;
|
||||
|
||||
std::string best_usr;
|
||||
int best_score = INT_MIN;
|
||||
|
||||
// Scan constructors for the best possible match.
|
||||
for (const Constructor& ctor : ctors) {
|
||||
// If |param_type_desc| is empty and the constructor is as well, we don't
|
||||
// need to bother searching, as this is the match.
|
||||
if (param_type_desc.empty() && ctor.param_type_desc.empty()) {
|
||||
best_usr = ctor.usr;
|
||||
break;
|
||||
}
|
||||
|
||||
// Weight matching parameter length heavily, as it is more accurate than
|
||||
// the fuzzy type matching approach.
|
||||
int score = 0;
|
||||
if (param_type_desc.size() == ctor.param_type_desc.size())
|
||||
score += param_type_desc.size() * 1000;
|
||||
|
||||
// Do prefix-based match on parameter type description. This works well in
|
||||
// practice because clang appends qualifiers to the end of the type, ie,
|
||||
// |foo *&&|
|
||||
for (int i = 0;
|
||||
i < std::min(param_type_desc.size(), ctor.param_type_desc.size());
|
||||
++i) {
|
||||
score += count_matching_prefix_length(param_type_desc[i].c_str(),
|
||||
ctor.param_type_desc[i].c_str());
|
||||
}
|
||||
|
||||
if (score > best_score) {
|
||||
best_usr = ctor.usr;
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!best_usr.empty());
|
||||
return best_usr;
|
||||
}
|
||||
};
|
||||
|
||||
struct IndexParam {
|
||||
std::unordered_set<CXFile> seen_cx_files;
|
||||
std::vector<std::string> seen_files;
|
||||
@ -107,6 +214,7 @@ struct IndexParam {
|
||||
|
||||
FileConsumer* file_consumer = nullptr;
|
||||
NamespaceHelper ns;
|
||||
ConstructorCache ctors;
|
||||
|
||||
IndexParam(clang::TranslationUnit* tu, FileConsumer* file_consumer)
|
||||
: tu(tu), file_consumer(file_consumer) {}
|
||||
@ -875,12 +983,19 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
clang_indexLoc_getCXSourceLocation(decl->loc)))
|
||||
return;
|
||||
|
||||
IndexParam* param = static_cast<IndexParam*>(client_data);
|
||||
|
||||
// Track all constructor declarations, as we may need to use it to manually
|
||||
// associate std::make_unique and the like as constructor invocations.
|
||||
if (decl->entityInfo->kind == CXIdxEntity_CXXConstructor) {
|
||||
param->ctors.NotifyConstructor(decl->cursor);
|
||||
}
|
||||
|
||||
assert(AreEqualLocations(decl->loc, decl->cursor));
|
||||
|
||||
CXFile file;
|
||||
clang_getSpellingLocation(clang_indexLoc_getCXSourceLocation(decl->loc),
|
||||
&file, nullptr, nullptr, nullptr);
|
||||
IndexParam* param = static_cast<IndexParam*>(client_data);
|
||||
IndexFile* db = ConsumeFile(param, file);
|
||||
if (!db)
|
||||
return;
|
||||
@ -1009,20 +1124,16 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
AddDeclTypeUsages(db, decl_cursor, decl->semanticContainer,
|
||||
decl->lexicalContainer);
|
||||
|
||||
func->is_constructor = decl->entityInfo->kind == CXIdxEntity_CXXConstructor;
|
||||
func->is_constructor =
|
||||
decl->entityInfo->kind == CXIdxEntity_CXXConstructor;
|
||||
|
||||
// Add parameter list if we haven't seen this function before.
|
||||
//
|
||||
// note: If the function has no parameters, this block will be rerun
|
||||
// every time we see the function. Performance should hopefully be fine
|
||||
// but it may be a possible optimization.
|
||||
if (func->parameter_type_descriptions.empty()) {
|
||||
for (clang::Cursor arg : decl_cursor.get_arguments()) {
|
||||
if (arg.get_kind() == CXCursor_ParmDecl) {
|
||||
func->parameter_type_descriptions.push_back(arg.get_type_description());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (func->parameter_type_descriptions.empty())
|
||||
func->parameter_type_descriptions = BuildTypeDesc(decl_cursor);
|
||||
|
||||
// Add definition or declaration. This is a bit tricky because we treat
|
||||
// template specializations as declarations, even though they are
|
||||
@ -1378,6 +1489,50 @@ void indexEntityReference(CXClientData client_data,
|
||||
AddFuncRef(&called->callers, IndexFuncRef(loc_spelling, is_implicit));
|
||||
}
|
||||
|
||||
// Checks if |str| starts with |start|. Ignores case.
|
||||
auto str_begin = [](const char* start, const char* str) {
|
||||
while (*start && *str) {
|
||||
char a = tolower(*start);
|
||||
char b = tolower(*str);
|
||||
if (a != b)
|
||||
return false;
|
||||
++start;
|
||||
++str;
|
||||
}
|
||||
return !*start;
|
||||
};
|
||||
|
||||
bool is_template = ref->referencedEntity->templateKind !=
|
||||
CXIdxEntityCXXTemplateKind::CXIdxEntity_NonTemplate;
|
||||
if (is_template && str_begin("make", ref->referencedEntity->name)) {
|
||||
// Try to find the return type of called function. That type will have
|
||||
// the constructor function we add a usage to.
|
||||
optional<clang::Cursor> opt_found_type = FindType(ref->cursor);
|
||||
if (opt_found_type) {
|
||||
std::string ctor_type_usr =
|
||||
opt_found_type->get_referenced().get_usr();
|
||||
clang::Cursor call_cursor = ref->cursor;
|
||||
|
||||
// Build a type description from the parameters of the call, so we
|
||||
// can try to find a constructor with the same type description.
|
||||
std::vector<std::string> call_type_desc;
|
||||
for (clang::Type type : call_cursor.get_type().get_arguments()) {
|
||||
std::string type_desc = type.get_spelling();
|
||||
if (!type_desc.empty())
|
||||
call_type_desc.push_back(type_desc);
|
||||
}
|
||||
|
||||
// Try to find the constructor and add a reference.
|
||||
optional<std::string> ctor_usr =
|
||||
param->ctors.TryFindConstructorUsr(ctor_type_usr, call_type_desc);
|
||||
if (ctor_usr) {
|
||||
IndexFunc* ctor = db->Resolve(db->ToFuncId(*ctor_usr));
|
||||
AddFuncRef(&ctor->callers,
|
||||
IndexFuncRef(loc_spelling, true /*is_implicit*/));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,6 @@ Cursor Cursor::get_semantic_parent() const {
|
||||
|
||||
std::vector<Cursor> Cursor::get_arguments() const {
|
||||
int size = clang_Cursor_getNumArguments(cx_cursor);
|
||||
assert(size >= 0);
|
||||
if (size < 0)
|
||||
return std::vector<Cursor>();
|
||||
|
||||
|
14
src/test.cc
14
src/test.cc
@ -121,19 +121,7 @@ void RunTests() {
|
||||
float memory_after = -1.;
|
||||
|
||||
{
|
||||
// if (path != "tests/templates/specialized_func_definition.cc") continue;
|
||||
// if (path !=
|
||||
// "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc")
|
||||
// continue; if (path != "tests/multi_file/funky_enum.cc") continue; if
|
||||
// (path != "tests/multi_file/simple_impl.cc") continue; if (path !=
|
||||
// "tests/inheritance/interface_pure_virtual.cc") continue; if (path !=
|
||||
// "tests/_empty_test.cc") continue; if (path !=
|
||||
// "tests/declaration_vs_definition/func_associated_function_params.cc")
|
||||
// continue;
|
||||
|
||||
// if (path !=
|
||||
// "tests/templates/template_class_type_usage_folded_into_one.cc")
|
||||
// continue; path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
||||
// if (path != "tests/constructors/make_functions.cc") continue;
|
||||
|
||||
Config config;
|
||||
FileConsumer::SharedState file_consumer_shared;
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include "make_functions.h"
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T* MakeUnique(Args&&... args) {
|
||||
return nullptr;
|
||||
@ -8,14 +10,6 @@ T* maKE_NoRefs(Args... args) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct Bar {};
|
||||
class Foobar {
|
||||
public:
|
||||
Foobar() {}
|
||||
Foobar(int) {}
|
||||
Foobar(int&&, Bar*, bool*) {}
|
||||
Foobar(int, Bar*, bool*) {}
|
||||
};
|
||||
void caller22() {
|
||||
MakeUnique<Foobar>();
|
||||
MakeUnique<Foobar>(1);
|
||||
@ -26,42 +20,103 @@ void caller22() {
|
||||
// TODO: Eliminate the extra entries in the "types" array here. They come from
|
||||
// the template function definitions.
|
||||
|
||||
// Foobar is defined in a separate file to ensure that we can attribute
|
||||
// MakeUnique calls across translation units.
|
||||
|
||||
/*
|
||||
OUTPUT:
|
||||
OUTPUT: make_functions.h
|
||||
{
|
||||
"dependencies": ["C:/Users/jacob/Desktop/cquery/tests/constructors/make_functions.cc"],
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:make_functions.cc@10",
|
||||
"uses": ["2:1-2:2"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:make_functions.cc@22",
|
||||
"uses": ["2:15-2:19"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:make_functions.cc@108",
|
||||
"uses": ["7:1-7:2"]
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:make_functions.cc@120",
|
||||
"uses": ["7:16-7:20"]
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:@S@Bar",
|
||||
"short_name": "Bar",
|
||||
"detailed_name": "Bar",
|
||||
"definition_spelling": "11:8-11:11",
|
||||
"definition_extent": "11:1-11:14",
|
||||
"uses": ["11:8-11:11", "16:17-16:20", "17:15-17:18", "22:29-22:32", "23:30-23:33"]
|
||||
"definition_spelling": "1:8-1:11",
|
||||
"definition_extent": "1:1-1:14",
|
||||
"uses": ["1:8-1:11", "7:17-7:20", "8:15-8:18"]
|
||||
}, {
|
||||
"id": 5,
|
||||
"id": 1,
|
||||
"usr": "c:@S@Foobar",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "Foobar",
|
||||
"definition_spelling": "12:7-12:13",
|
||||
"definition_extent": "12:1-18:2",
|
||||
"funcs": [2, 3, 4, 5],
|
||||
"uses": ["12:7-12:13", "14:3-14:9", "15:3-15:9", "16:3-16:9", "17:3-17:9", "20:14-20:20", "21:14-21:20", "22:14-22:20", "23:15-23:21"]
|
||||
"definition_spelling": "3:7-3:13",
|
||||
"definition_extent": "3:1-9:2",
|
||||
"funcs": [0, 1, 2, 3],
|
||||
"uses": ["3:7-3:13", "5:3-5:9", "6:3-6:9", "7:3-7:9", "8:3-8:9"]
|
||||
}],
|
||||
"funcs": [{
|
||||
"id": 0,
|
||||
"usr": "c:@S@Foobar@F@Foobar#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar()",
|
||||
"is_constructor": true,
|
||||
"definition_spelling": "5:3-5:9",
|
||||
"definition_extent": "5:3-5:14",
|
||||
"declaring_type": 1
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:@S@Foobar@F@Foobar#I#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar(int)",
|
||||
"is_constructor": true,
|
||||
"parameter_type_descriptions": ["int"],
|
||||
"definition_spelling": "6:3-6:9",
|
||||
"definition_extent": "6:3-6:17",
|
||||
"declaring_type": 1
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:@S@Foobar@F@Foobar#&&I#*$@S@Bar#*b#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar(int &&, Bar *, bool *)",
|
||||
"is_constructor": true,
|
||||
"parameter_type_descriptions": ["int &&", "Bar *", "bool *"],
|
||||
"definition_spelling": "7:3-7:9",
|
||||
"definition_extent": "7:3-7:32",
|
||||
"declaring_type": 1
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:@S@Foobar@F@Foobar#I#*$@S@Bar#*b#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar(int, Bar *, bool *)",
|
||||
"is_constructor": true,
|
||||
"parameter_type_descriptions": ["int", "Bar *", "bool *"],
|
||||
"definition_spelling": "8:3-8:9",
|
||||
"definition_extent": "8:3-8:30",
|
||||
"declaring_type": 1
|
||||
}]
|
||||
}
|
||||
OUTPUT: make_functions.cc
|
||||
{
|
||||
"includes": [{
|
||||
"line": 1,
|
||||
"resolved_path": "C:/Users/jacob/Desktop/cquery/tests/constructors/make_functions.h"
|
||||
}],
|
||||
"dependencies": ["C:/Users/jacob/Desktop/cquery/tests/constructors/make_functions.h"],
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:make_functions.cc@41",
|
||||
"uses": ["4:1-4:2"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:make_functions.cc@53",
|
||||
"uses": ["4:15-4:19"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:make_functions.cc@139",
|
||||
"uses": ["9:1-9:2"]
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:make_functions.cc@151",
|
||||
"uses": ["9:16-9:20"]
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:@S@Foobar",
|
||||
"uses": ["14:14-14:20", "15:14-15:20", "16:14-16:20", "17:15-17:21"]
|
||||
}, {
|
||||
"id": 5,
|
||||
"usr": "c:@S@Bar",
|
||||
"uses": ["16:29-16:32", "17:30-17:33"]
|
||||
}],
|
||||
"funcs": [{
|
||||
"id": 0,
|
||||
@ -70,9 +125,9 @@ OUTPUT:
|
||||
"detailed_name": "T *MakeUnique(Args &&...)",
|
||||
"is_constructor": false,
|
||||
"parameter_type_descriptions": ["Args &&..."],
|
||||
"definition_spelling": "2:4-2:14",
|
||||
"definition_extent": "2:1-4:2",
|
||||
"callers": ["6@20:3-20:13", "6@21:3-21:13", "6@22:3-22:13"]
|
||||
"definition_spelling": "4:4-4:14",
|
||||
"definition_extent": "4:1-6:2",
|
||||
"callers": ["2@14:3-14:13", "2@15:3-15:13", "2@16:3-16:13"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:@FT@>2#T#pTmaKE_NoRefs#Pt0.1#*t0.0#",
|
||||
@ -80,78 +135,59 @@ OUTPUT:
|
||||
"detailed_name": "T *maKE_NoRefs(Args...)",
|
||||
"is_constructor": false,
|
||||
"parameter_type_descriptions": ["Args..."],
|
||||
"definition_spelling": "7:4-7:15",
|
||||
"definition_extent": "7:1-9:2",
|
||||
"callers": ["6@23:3-23:14"]
|
||||
"definition_spelling": "9:4-9:15",
|
||||
"definition_extent": "9:1-11:2",
|
||||
"callers": ["2@17:3-17:14"]
|
||||
}, {
|
||||
"id": 2,
|
||||
"usr": "c:@S@Foobar@F@Foobar#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar()",
|
||||
"is_constructor": true,
|
||||
"definition_spelling": "14:3-14:9",
|
||||
"definition_extent": "14:3-14:14",
|
||||
"declaring_type": 5
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:@S@Foobar@F@Foobar#I#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar(int)",
|
||||
"is_constructor": true,
|
||||
"parameter_type_descriptions": ["int"],
|
||||
"definition_spelling": "15:3-15:9",
|
||||
"definition_extent": "15:3-15:17",
|
||||
"declaring_type": 5
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:@S@Foobar@F@Foobar#&&I#*$@S@Bar#*b#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar(int &&, Bar *, bool *)",
|
||||
"is_constructor": true,
|
||||
"parameter_type_descriptions": ["int &&", "Bar *", "bool *"],
|
||||
"definition_spelling": "16:3-16:9",
|
||||
"definition_extent": "16:3-16:32",
|
||||
"declaring_type": 5
|
||||
}, {
|
||||
"id": 5,
|
||||
"usr": "c:@S@Foobar@F@Foobar#I#*$@S@Bar#*b#",
|
||||
"short_name": "Foobar",
|
||||
"detailed_name": "void Foobar::Foobar(int, Bar *, bool *)",
|
||||
"is_constructor": true,
|
||||
"parameter_type_descriptions": ["int", "Bar *", "bool *"],
|
||||
"definition_spelling": "17:3-17:9",
|
||||
"definition_extent": "17:3-17:30",
|
||||
"declaring_type": 5
|
||||
}, {
|
||||
"id": 6,
|
||||
"usr": "c:@F@caller22#",
|
||||
"short_name": "caller22",
|
||||
"detailed_name": "void caller22()",
|
||||
"is_constructor": false,
|
||||
"definition_spelling": "19:6-19:14",
|
||||
"definition_extent": "19:1-24:2",
|
||||
"callees": ["0@20:3-20:13", "0@21:3-21:13", "0@22:3-22:13", "1@23:3-23:14"]
|
||||
"definition_spelling": "13:6-13:14",
|
||||
"definition_extent": "13:1-18:2",
|
||||
"callees": ["0@14:3-14:13", "0@15:3-15:13", "0@16:3-16:13", "1@17:3-17:14"]
|
||||
}, {
|
||||
"id": 3,
|
||||
"usr": "c:@S@Foobar@F@Foobar#",
|
||||
"is_constructor": false,
|
||||
"callers": ["~-1@14:3-14:13"]
|
||||
}, {
|
||||
"id": 4,
|
||||
"usr": "c:@S@Foobar@F@Foobar#I#",
|
||||
"is_constructor": false,
|
||||
"callers": ["~-1@15:3-15:13"]
|
||||
}, {
|
||||
"id": 5,
|
||||
"usr": "c:@S@Foobar@F@Foobar#&&I#*$@S@Bar#*b#",
|
||||
"is_constructor": false,
|
||||
"callers": ["~-1@16:3-16:13"]
|
||||
}, {
|
||||
"id": 6,
|
||||
"usr": "c:@S@Foobar@F@Foobar#I#*$@S@Bar#*b#",
|
||||
"is_constructor": false,
|
||||
"callers": ["~-1@17:3-17:14"]
|
||||
}],
|
||||
"vars": [{
|
||||
"id": 0,
|
||||
"usr": "c:make_functions.cc@55@FT@>2#T#pTMakeUnique#P&&t0.1#*t0.0#@args",
|
||||
"usr": "c:make_functions.cc@86@FT@>2#T#pTMakeUnique#P&&t0.1#*t0.0#@args",
|
||||
"short_name": "args",
|
||||
"detailed_name": "Args &&... args",
|
||||
"definition_spelling": "2:25-2:29",
|
||||
"definition_extent": "2:15-2:29",
|
||||
"definition_spelling": "4:25-4:29",
|
||||
"definition_extent": "4:15-4:29",
|
||||
"is_local": true,
|
||||
"is_macro": false,
|
||||
"uses": ["2:25-2:29"]
|
||||
"uses": ["4:25-4:29"]
|
||||
}, {
|
||||
"id": 1,
|
||||
"usr": "c:make_functions.cc@154@FT@>2#T#pTmaKE_NoRefs#Pt0.1#*t0.0#@args",
|
||||
"usr": "c:make_functions.cc@185@FT@>2#T#pTmaKE_NoRefs#Pt0.1#*t0.0#@args",
|
||||
"short_name": "args",
|
||||
"detailed_name": "Args... args",
|
||||
"definition_spelling": "7:24-7:28",
|
||||
"definition_extent": "7:16-7:28",
|
||||
"definition_spelling": "9:24-9:28",
|
||||
"definition_extent": "9:16-9:28",
|
||||
"is_local": true,
|
||||
"is_macro": false,
|
||||
"uses": ["7:24-7:28"]
|
||||
"uses": ["9:24-9:28"]
|
||||
}]
|
||||
}
|
||||
*/
|
||||
|
10
tests/constructors/make_functions.h
Normal file
10
tests/constructors/make_functions.h
Normal file
@ -0,0 +1,10 @@
|
||||
struct Bar {};
|
||||
|
||||
class Foobar {
|
||||
public:
|
||||
Foobar() {}
|
||||
Foobar(int) {}
|
||||
Foobar(int&&, Bar*, bool*) {}
|
||||
Foobar(int, Bar*, bool*) {}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user