mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-31 09:50:26 +00:00
better template indexing
This commit is contained in:
parent
d403d7ad96
commit
8e36152406
@ -604,7 +604,7 @@ void LanguageServerMain(std::string process_name) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int mai232n(int argc, char** argv) {
|
||||||
// We need to write to stdout in binary mode because in Windows, writing
|
// We need to write to stdout in binary mode because in Windows, writing
|
||||||
// \n will implicitly write \r\n. Language server API will ignore a
|
// \n will implicitly write \r\n. Language server API will ignore a
|
||||||
// \r\r\n split request.
|
// \r\r\n split request.
|
||||||
|
108
indexer.cpp
108
indexer.cpp
@ -353,12 +353,9 @@ void VisitDeclForTypeUsageVisitorHandler(clang::Cursor cursor, VisitDeclForTypeU
|
|||||||
param->has_processed_any = true;
|
param->has_processed_any = true;
|
||||||
IndexedFile* db = param->db;
|
IndexedFile* db = param->db;
|
||||||
|
|
||||||
// TODO: Something in STL (type_traits)? reports an empty USR.
|
std::string referenced_usr = cursor.get_referenced().template_specialization_to_template_definition().get_usr();
|
||||||
std::string referenced_usr = cursor.get_referenced().get_usr();
|
|
||||||
if (referenced_usr == "")
|
|
||||||
return;
|
|
||||||
|
|
||||||
TypeId ref_type_id = db->ToTypeId(referenced_usr);
|
TypeId ref_type_id = db->ToTypeId(referenced_usr);
|
||||||
|
|
||||||
if (!param->initial_type)
|
if (!param->initial_type)
|
||||||
param->initial_type = ref_type_id;
|
param->initial_type = ref_type_id;
|
||||||
|
|
||||||
@ -392,7 +389,23 @@ clang::VisiterResult VisitDeclForTypeUsageVisitor(clang::Cursor cursor, clang::C
|
|||||||
return clang::VisiterResult::Continue;
|
return clang::VisiterResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<TypeId> ResolveDeclToType(IndexedFile* db, clang::Cursor decl_cursor,
|
// Finds the cursor associated with the declaration type of |cursor|. This strips
|
||||||
|
// qualifies from |cursor| (ie, Foo* => Foo) and removes template arguments
|
||||||
|
// (ie, Foo<A,B> => Foo<*,*>).
|
||||||
|
optional<TypeId> ResolveToDeclarationType(IndexedFile* db, clang::Cursor cursor) {
|
||||||
|
clang::Cursor declaration = cursor.get_type().strip_qualifiers().get_declaration();
|
||||||
|
declaration = declaration.template_specialization_to_template_definition();
|
||||||
|
std::string usr = declaration.get_usr();
|
||||||
|
if (usr != "")
|
||||||
|
return db->ToTypeId(usr);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add usages to any seen TypeRef or TemplateRef under the given |decl_cursor|. This
|
||||||
|
// returns the first seen TypeRef or TemplateRef value, which can be useful if trying
|
||||||
|
// to figure out ie, what a using statement refers to. If trying to generally resolve
|
||||||
|
// a cursor to a type, use ResolveToDeclarationType, which works in more scenarios.
|
||||||
|
optional<TypeId> AddDeclUsages(IndexedFile* db, clang::Cursor decl_cursor,
|
||||||
bool is_interesting, const CXIdxContainerInfo* semantic_container,
|
bool is_interesting, const CXIdxContainerInfo* semantic_container,
|
||||||
const CXIdxContainerInfo* lexical_container) {
|
const CXIdxContainerInfo* lexical_container) {
|
||||||
//
|
//
|
||||||
@ -415,7 +428,46 @@ optional<TypeId> ResolveDeclToType(IndexedFile* db, clang::Cursor decl_cursor,
|
|||||||
// TypeRef struct S2
|
// TypeRef struct S2
|
||||||
// TypeRef struct S2
|
// TypeRef struct S2
|
||||||
//
|
//
|
||||||
|
//
|
||||||
|
// Here is another example:
|
||||||
|
//
|
||||||
|
// enum A {};
|
||||||
|
// enum B {};
|
||||||
|
//
|
||||||
|
// template<typename T>
|
||||||
|
// struct Foo {
|
||||||
|
// struct Inner {};
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// Foo<A>::Inner a;
|
||||||
|
// Foo<B> b;
|
||||||
|
//
|
||||||
|
// =>
|
||||||
|
//
|
||||||
|
// EnumDecl A
|
||||||
|
// EnumDecl B
|
||||||
|
// ClassTemplate Foo
|
||||||
|
// TemplateTypeParameter T
|
||||||
|
// StructDecl Inner
|
||||||
|
// VarDecl a
|
||||||
|
// TemplateRef Foo
|
||||||
|
// TypeRef enum A
|
||||||
|
// TypeRef struct Foo<enum A>::Inner
|
||||||
|
// CallExpr Inner
|
||||||
|
// VarDecl b
|
||||||
|
// TemplateRef Foo
|
||||||
|
// TypeRef enum B
|
||||||
|
// CallExpr Foo
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Determining the actual type of the variable/declaration from just the
|
||||||
|
// children is tricky. Doing so would require looking up the template
|
||||||
|
// definition associated with a TemplateRef, figuring out how many children
|
||||||
|
// it has, and then skipping that many TypeRef values. This also has to work
|
||||||
|
// with the example below (skipping the last TypeRef). As a result, we
|
||||||
|
// determine variable types using |ResolveToDeclarationType|.
|
||||||
|
//
|
||||||
|
//
|
||||||
// We skip the last type reference for methods/variables which are defined
|
// We skip the last type reference for methods/variables which are defined
|
||||||
// out-of-line w.r.t. the parent type.
|
// out-of-line w.r.t. the parent type.
|
||||||
//
|
//
|
||||||
@ -449,7 +501,12 @@ optional<TypeId> ResolveDeclToType(IndexedFile* db, clang::Cursor decl_cursor,
|
|||||||
else {
|
else {
|
||||||
// If we are not processing the last type ref, it *must* be a TypeRef (ie,
|
// If we are not processing the last type ref, it *must* be a TypeRef (ie,
|
||||||
// and not a TemplateRef).
|
// and not a TemplateRef).
|
||||||
assert(!param.previous_cursor.has_value() ||
|
//
|
||||||
|
// We will not visit every child if the is_interseting is false, so previous_cursor
|
||||||
|
// may not point to the last TemplateRef.
|
||||||
|
assert(
|
||||||
|
is_interesting == false ||
|
||||||
|
param.previous_cursor.has_value() == false ||
|
||||||
param.previous_cursor.value().get_kind() == CXCursor_TypeRef);
|
param.previous_cursor.value().get_kind() == CXCursor_TypeRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,12 +553,15 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
var_def->def.declaration = decl_loc;
|
var_def->def.declaration = decl_loc;
|
||||||
var_def->uses.push_back(decl_loc);
|
var_def->uses.push_back(decl_loc);
|
||||||
|
|
||||||
|
//std::cerr << std::endl << "Visiting declaration" << std::endl;
|
||||||
|
//Dump(decl_cursor);
|
||||||
|
|
||||||
// Declaring variable type information. Note that we do not insert an
|
// Declaring variable type information. Note that we do not insert an
|
||||||
// interesting reference for parameter declarations - that is handled when
|
// interesting reference for parameter declarations - that is handled when
|
||||||
// the function declaration is encountered since we won't receive ParmDecl
|
// the function declaration is encountered since we won't receive ParmDecl
|
||||||
// declarations for unnamed parameters.
|
// declarations for unnamed parameters.
|
||||||
optional<TypeId> var_type = ResolveDeclToType(db, decl_cursor, decl_cursor.get_kind() != CXCursor_ParmDecl /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
AddDeclUsages(db, decl_cursor, decl_cursor.get_kind() != CXCursor_ParmDecl /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
||||||
|
optional<TypeId> var_type = ResolveToDeclarationType(db, decl_cursor);
|
||||||
if (var_type.has_value())
|
if (var_type.has_value())
|
||||||
var_def->def.variable_type = var_type.value();
|
var_def->def.variable_type = var_type.value();
|
||||||
|
|
||||||
@ -570,7 +630,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
|
|
||||||
// We don't actually need to know the return type, but we need to mark it
|
// We don't actually need to know the return type, but we need to mark it
|
||||||
// as an interesting usage.
|
// as an interesting usage.
|
||||||
ResolveDeclToType(db, decl_cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
AddDeclUsages(db, decl_cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
||||||
|
|
||||||
//TypeResolution ret_type = ResolveToType(db, decl_cursor.get_type().get_return_type());
|
//TypeResolution ret_type = ResolveToType(db, decl_cursor.get_type().get_return_type());
|
||||||
//if (ret_type.resolved_type)
|
//if (ret_type.resolved_type)
|
||||||
@ -592,7 +652,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
case CXCursor_ParmDecl:
|
case CXCursor_ParmDecl:
|
||||||
// We don't need to know the arg type, but we do want to mark it as
|
// We don't need to know the arg type, but we do want to mark it as
|
||||||
// an interesting usage.
|
// an interesting usage.
|
||||||
ResolveDeclToType(db, arg, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
AddDeclUsages(db, arg, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
||||||
|
|
||||||
//TypeResolution arg_type = ResolveToType(db, arg.get_type());
|
//TypeResolution arg_type = ResolveToType(db, arg.get_type());
|
||||||
//if (arg_type.resolved_type)
|
//if (arg_type.resolved_type)
|
||||||
@ -639,7 +699,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
case CXIdxEntity_Typedef:
|
case CXIdxEntity_Typedef:
|
||||||
case CXIdxEntity_CXXTypeAlias:
|
case CXIdxEntity_CXXTypeAlias:
|
||||||
{
|
{
|
||||||
optional<TypeId> alias_of = ResolveDeclToType(db, decl->cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
// Note we want to fetch the first TypeRef. Running ResolveCursorType(decl->cursor) would return
|
||||||
|
// the type of the typedef/using, not the type of the referenced type.
|
||||||
|
optional<TypeId> alias_of = AddDeclUsages(db, decl->cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
||||||
|
|
||||||
TypeId type_id = db->ToTypeId(decl->entityInfo->USR);
|
TypeId type_id = db->ToTypeId(decl->entityInfo->USR);
|
||||||
IndexedTypeDef* type_def = db->Resolve(type_id);
|
IndexedTypeDef* type_def = db->Resolve(type_id);
|
||||||
@ -702,7 +764,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
for (unsigned int i = 0; i < class_info->numBases; ++i) {
|
for (unsigned int i = 0; i < class_info->numBases; ++i) {
|
||||||
const CXIdxBaseClassInfo* base_class = class_info->bases[i];
|
const CXIdxBaseClassInfo* base_class = class_info->bases[i];
|
||||||
|
|
||||||
optional<TypeId> parent_type_id = ResolveDeclToType(db, base_class->cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
AddDeclUsages(db, base_class->cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
|
||||||
|
optional<TypeId> parent_type_id = ResolveToDeclarationType(db, base_class->cursor);
|
||||||
IndexedTypeDef* type_def = db->Resolve(type_id); // type_def ptr could be invalidated by ResolveDeclToType.
|
IndexedTypeDef* type_def = db->Resolve(type_id); // type_def ptr could be invalidated by ResolveDeclToType.
|
||||||
if (parent_type_id) {
|
if (parent_type_id) {
|
||||||
IndexedTypeDef* parent_type_def = db->Resolve(parent_type_id.value());
|
IndexedTypeDef* parent_type_def = db->Resolve(parent_type_id.value());
|
||||||
@ -749,9 +812,13 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re
|
|||||||
case CXIdxEntity_Variable:
|
case CXIdxEntity_Variable:
|
||||||
case CXIdxEntity_Field:
|
case CXIdxEntity_Field:
|
||||||
{
|
{
|
||||||
VarId var_id = db->ToVarId(ref->referencedEntity->cursor);
|
clang::Cursor referenced = ref->referencedEntity->cursor;
|
||||||
|
referenced = referenced.template_specialization_to_template_definition();
|
||||||
|
|
||||||
|
VarId var_id = db->ToVarId(referenced.get_usr());
|
||||||
IndexedVarDef* var_def = db->Resolve(var_id);
|
IndexedVarDef* var_def = db->Resolve(var_id);
|
||||||
var_def->uses.push_back(db->id_cache.Resolve(ref->loc, false /*interesting*/));
|
Location loc = db->id_cache.Resolve(ref->loc, false /*interesting*/);
|
||||||
|
var_def->uses.push_back(loc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,9 +872,13 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re
|
|||||||
Location our_loc = db->id_cache.Resolve(ref->loc, true /*is_interesting*/);
|
Location our_loc = db->id_cache.Resolve(ref->loc, true /*is_interesting*/);
|
||||||
if (!parent_loc.IsEqualTo(our_loc)) {
|
if (!parent_loc.IsEqualTo(our_loc)) {
|
||||||
IndexedFuncDef* called_def = db->Resolve(called_id);
|
IndexedFuncDef* called_def = db->Resolve(called_id);
|
||||||
|
// I suspect it is possible for the declaring type to be null
|
||||||
|
// when the class is invalid.
|
||||||
|
//if (called_def->def.declaring_type) {
|
||||||
assert(called_def->def.declaring_type.has_value());
|
assert(called_def->def.declaring_type.has_value());
|
||||||
IndexedTypeDef* type_def = db->Resolve(called_def->def.declaring_type.value());
|
IndexedTypeDef* type_def = db->Resolve(called_def->def.declaring_type.value());
|
||||||
type_def->AddUsage(our_loc);
|
type_def->AddUsage(our_loc);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -820,7 +891,10 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re
|
|||||||
case CXIdxEntity_Struct:
|
case CXIdxEntity_Struct:
|
||||||
case CXIdxEntity_CXXClass:
|
case CXIdxEntity_CXXClass:
|
||||||
{
|
{
|
||||||
TypeId referenced_id = db->ToTypeId(ref->referencedEntity->USR);
|
clang::Cursor referenced = ref->referencedEntity->cursor;
|
||||||
|
referenced = referenced.template_specialization_to_template_definition();
|
||||||
|
TypeId referenced_id = db->ToTypeId(referenced.get_usr());
|
||||||
|
|
||||||
IndexedTypeDef* referenced_def = db->Resolve(referenced_id);
|
IndexedTypeDef* referenced_def = db->Resolve(referenced_id);
|
||||||
|
|
||||||
// We will not get a declaration visit for forward declared types. Try to mark them as non-bad
|
// We will not get a declaration visit for forward declared types. Try to mark them as non-bad
|
||||||
@ -895,7 +969,7 @@ IndexedFile Parse(std::string filename, std::vector<std::string> args, bool dump
|
|||||||
NamespaceHelper ns;
|
NamespaceHelper ns;
|
||||||
IndexParam param(&db, &ns);
|
IndexParam param(&db, &ns);
|
||||||
clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks),
|
clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks),
|
||||||
CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession, tu.cx_tu);
|
CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession | CXIndexOpt_IndexImplicitTemplateInstantiations, tu.cx_tu);
|
||||||
|
|
||||||
clang_IndexAction_dispose(index_action);
|
clang_IndexAction_dispose(index_action);
|
||||||
|
|
||||||
|
@ -27,6 +27,10 @@ bool Type::is_fundamental() const {
|
|||||||
cx_type.kind <= CXType_LastBuiltin;
|
cx_type.kind <= CXType_LastBuiltin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CXCursor Type::get_declaration() const {
|
||||||
|
return clang_getTypeDeclaration(cx_type);
|
||||||
|
}
|
||||||
|
|
||||||
std::string Type::get_usr() const {
|
std::string Type::get_usr() const {
|
||||||
return clang::Cursor(clang_getTypeDeclaration(cx_type)).get_usr();
|
return clang::Cursor(clang_getTypeDeclaration(cx_type)).get_usr();
|
||||||
}
|
}
|
||||||
@ -133,9 +137,10 @@ bool Cursor::is_definition() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cursor Cursor::template_specialization_to_template_definition() const {
|
Cursor Cursor::template_specialization_to_template_definition() const {
|
||||||
// TODO: Should we return this same cursor if this is not a template? We
|
CXCursor definition = clang_getSpecializedCursorTemplate(cx_cursor);
|
||||||
// can probably check USR to do that.
|
if (definition.kind == CXCursor_FirstInvalid)
|
||||||
return clang_getSpecializedCursorTemplate(cx_cursor);
|
return cx_cursor;
|
||||||
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cursor Cursor::get_referenced() const {
|
Cursor Cursor::get_referenced() const {
|
||||||
|
@ -21,6 +21,8 @@ public:
|
|||||||
// Returns true if this is a fundamental type like int.
|
// Returns true if this is a fundamental type like int.
|
||||||
bool is_fundamental() const;
|
bool is_fundamental() const;
|
||||||
|
|
||||||
|
// clang::Cursor is not defined so we have to return CXCursor
|
||||||
|
CXCursor get_declaration() const;
|
||||||
std::string get_usr() const;
|
std::string get_usr() const;
|
||||||
std::string get_spelling() const;
|
std::string get_spelling() const;
|
||||||
|
|
||||||
@ -58,7 +60,14 @@ public:
|
|||||||
|
|
||||||
bool is_definition() const;
|
bool is_definition() const;
|
||||||
|
|
||||||
|
// If the given cursor points to a template specialization, this
|
||||||
|
// will return the cursor pointing to the template definition.
|
||||||
|
// If the given cursor is not a template specialization, this will
|
||||||
|
// just return the same cursor.
|
||||||
|
//
|
||||||
|
// This means it is always safe to call this method.
|
||||||
Cursor template_specialization_to_template_definition() const;
|
Cursor template_specialization_to_template_definition() const;
|
||||||
|
|
||||||
Cursor get_referenced() const;
|
Cursor get_referenced() const;
|
||||||
Cursor get_canonical() const;
|
Cursor get_canonical() const;
|
||||||
Cursor get_definition() const;
|
Cursor get_definition() const;
|
||||||
|
12
test.cc
12
test.cc
@ -82,7 +82,7 @@ void VerifySerializeToFrom(IndexedFile* file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main222(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// TODO: Assert that we need to be on clang >= 3.9.1
|
// TODO: Assert that we need to be on clang >= 3.9.1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -94,8 +94,12 @@ int main222(int argc, char** argv) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
for (std::string path : GetFilesInFolder("tests", true /*add_folder_to_path*/)) {
|
for (std::string path : GetFilesInFolder("tests", true /*add_folder_to_path*/)) {
|
||||||
//if (path != "tests/usage/type_usage_declare_field.cc") continue;
|
//if (path == "tests/foobar.cc") continue;
|
||||||
path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
//if (path == "tests/inheritance/class_inherit_templated_parent.cc") continue;
|
||||||
|
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;
|
||||||
|
|
||||||
|
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;
|
||||||
|
//path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
||||||
|
|
||||||
// Parse expected output from the test, parse it into JSON document.
|
// Parse expected output from the test, parse it into JSON document.
|
||||||
std::string expected_output;
|
std::string expected_output;
|
||||||
@ -105,7 +109,7 @@ int main222(int argc, char** argv) {
|
|||||||
|
|
||||||
// Run test.
|
// Run test.
|
||||||
std::cout << "[START] " << path << std::endl;
|
std::cout << "[START] " << path << std::endl;
|
||||||
IndexedFile db = Parse(path, {}, true /*dump_ast*/);
|
IndexedFile db = Parse(path, {}, false /*dump_ast*/);
|
||||||
VerifySerializeToFrom(&db);
|
VerifySerializeToFrom(&db);
|
||||||
std::string actual_output = db.ToString();
|
std::string actual_output = db.ToString();
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ OUTPUT:
|
|||||||
"short_name": "A",
|
"short_name": "A",
|
||||||
"qualified_name": "Foo::A",
|
"qualified_name": "Foo::A",
|
||||||
"definition": "1:2:3",
|
"definition": "1:2:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:2:3"]
|
"uses": ["1:2:3"]
|
||||||
}, {
|
}, {
|
||||||
@ -30,6 +31,7 @@ OUTPUT:
|
|||||||
"short_name": "B",
|
"short_name": "B",
|
||||||
"qualified_name": "Foo::B",
|
"qualified_name": "Foo::B",
|
||||||
"definition": "1:3:3",
|
"definition": "1:3:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:3:3"]
|
"uses": ["1:3:3"]
|
||||||
}]
|
}]
|
||||||
|
@ -22,6 +22,7 @@ OUTPUT:
|
|||||||
"short_name": "A",
|
"short_name": "A",
|
||||||
"qualified_name": "Foo::A",
|
"qualified_name": "Foo::A",
|
||||||
"definition": "1:2:3",
|
"definition": "1:2:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:2:3"]
|
"uses": ["1:2:3"]
|
||||||
}, {
|
}, {
|
||||||
@ -30,6 +31,7 @@ OUTPUT:
|
|||||||
"short_name": "B",
|
"short_name": "B",
|
||||||
"qualified_name": "Foo::B",
|
"qualified_name": "Foo::B",
|
||||||
"definition": "1:3:3",
|
"definition": "1:3:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:3:3"]
|
"uses": ["1:3:3"]
|
||||||
}]
|
}]
|
||||||
|
@ -22,6 +22,7 @@ OUTPUT:
|
|||||||
"short_name": "A",
|
"short_name": "A",
|
||||||
"qualified_name": "Foo::A",
|
"qualified_name": "Foo::A",
|
||||||
"definition": "1:2:3",
|
"definition": "1:2:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:2:3"]
|
"uses": ["1:2:3"]
|
||||||
}, {
|
}, {
|
||||||
@ -30,6 +31,7 @@ OUTPUT:
|
|||||||
"short_name": "B",
|
"short_name": "B",
|
||||||
"qualified_name": "Foo::B",
|
"qualified_name": "Foo::B",
|
||||||
"definition": "1:3:3",
|
"definition": "1:3:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:3:3"]
|
"uses": ["1:3:3"]
|
||||||
}]
|
}]
|
||||||
|
@ -24,6 +24,7 @@ OUTPUT:
|
|||||||
"short_name": "A",
|
"short_name": "A",
|
||||||
"qualified_name": "Foo::A",
|
"qualified_name": "Foo::A",
|
||||||
"definition": "1:2:3",
|
"definition": "1:2:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:2:3", "1:6:14"]
|
"uses": ["1:2:3", "1:6:14"]
|
||||||
}, {
|
}, {
|
||||||
@ -32,6 +33,7 @@ OUTPUT:
|
|||||||
"short_name": "B",
|
"short_name": "B",
|
||||||
"qualified_name": "Foo::B",
|
"qualified_name": "Foo::B",
|
||||||
"definition": "1:3:3",
|
"definition": "1:3:3",
|
||||||
|
"variable_type": 0,
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"uses": ["1:3:3"]
|
"uses": ["1:3:3"]
|
||||||
}, {
|
}, {
|
||||||
|
281
tests/foobar.cc
281
tests/foobar.cc
@ -1,40 +1,267 @@
|
|||||||
void called(int a);
|
enum A {};
|
||||||
|
enum B {};
|
||||||
|
|
||||||
int gen() { return 1; }
|
template<typename T>
|
||||||
|
struct Foo {
|
||||||
|
struct Inner {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Foo<A>::Inner a;
|
||||||
|
Foo<B> b;
|
||||||
|
|
||||||
|
|
||||||
|
#if false
|
||||||
|
// We could store how many template parameters Foo has and then skip that many TypeRefs...,
|
||||||
|
// if there was still a TypeRef after (and we are not ignoring it) then we know
|
||||||
|
// that is the variable type.
|
||||||
|
|
||||||
|
EnumDecl A
|
||||||
|
EnumDecl B
|
||||||
|
ClassTemplate Foo
|
||||||
|
TemplateTypeParameter T
|
||||||
|
StructDecl Inner
|
||||||
|
VarDecl a
|
||||||
|
TemplateRef Foo
|
||||||
|
TypeRef enum A
|
||||||
|
TypeRef struct Foo<enum A>::Inner
|
||||||
|
CallExpr Inner
|
||||||
|
VarDecl b
|
||||||
|
TemplateRef Foo
|
||||||
|
TypeRef enum B
|
||||||
|
CallExpr Foo
|
||||||
|
#endif
|
||||||
|
|
||||||
void foo() {
|
|
||||||
called(gen() * gen());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
OUTPUT:
|
OUTPUT:
|
||||||
{
|
{
|
||||||
"types": [],
|
"types": [{
|
||||||
"functions": [{
|
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"usr": "c:@F@called#I#",
|
"usr": "c:@E@A",
|
||||||
"short_name": "called",
|
"short_name": "A",
|
||||||
"qualified_name": "called",
|
"qualified_name": "A",
|
||||||
"declarations": ["1:1:6"],
|
"definition": "1:1:6",
|
||||||
"callers": ["2@1:6:3"],
|
"uses": ["*1:1:6", "*1:9:5"]
|
||||||
"uses": ["1:1:6", "1:6:3"]
|
|
||||||
}, {
|
}, {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"usr": "c:@F@gen#",
|
"usr": "c:@E@B",
|
||||||
"short_name": "gen",
|
"short_name": "B",
|
||||||
"qualified_name": "gen",
|
"qualified_name": "B",
|
||||||
"definition": "1:3:5",
|
"definition": "1:2:6",
|
||||||
"callers": ["2@1:6:10", "2@1:6:18"],
|
"uses": ["*1:2:6", "*1:10:5"]
|
||||||
"uses": ["1:3:5", "1:6:10", "1:6:18"]
|
|
||||||
}, {
|
}, {
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"usr": "c:@F@foo#",
|
"usr": "c:@ST>1#T@Foo",
|
||||||
"short_name": "foo",
|
"short_name": "Foo",
|
||||||
"qualified_name": "foo",
|
"qualified_name": "Foo",
|
||||||
"definition": "1:5:6",
|
"definition": "1:5:8",
|
||||||
"callees": ["0@1:6:3", "1@1:6:10", "1@1:6:18"],
|
"uses": ["*1:5:8", "*1:9:1", "*1:10:1"]
|
||||||
"uses": ["1:5:6"]
|
}, {
|
||||||
|
"id": 3,
|
||||||
|
"usr": "c:@ST>1#T@Foo@S@Inner",
|
||||||
|
"short_name": "Inner",
|
||||||
|
"qualified_name": "Foo::Inner",
|
||||||
|
"definition": "1:6:10",
|
||||||
|
"uses": ["*1:6:10", "*1:9:9"]
|
||||||
}],
|
}],
|
||||||
"variables": []
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:9:15",
|
||||||
|
"variable_type": 3,
|
||||||
|
"uses": ["1:9:15"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:10:8",
|
||||||
|
"variable_type": 2,
|
||||||
|
"uses": ["1:10:8"]
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if false
|
||||||
|
namespace ns {
|
||||||
|
enum VarType {};
|
||||||
|
|
||||||
|
template<typename _>
|
||||||
|
struct Holder {
|
||||||
|
static constexpr VarType static_var = (VarType)0x0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _>
|
||||||
|
const typename VarType Holder<_>::static_var;
|
||||||
|
|
||||||
|
|
||||||
|
int Foo = Holder<int>::static_var;
|
||||||
|
int Foo2 = Holder<int>::static_var;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: we are not marking interesting usage for a CStyleCastExpr
|
||||||
|
// TODO: we are resoling templates in a weird way (should be 1 type)
|
||||||
|
#if false
|
||||||
|
Namespace ns
|
||||||
|
EnumDecl VarType
|
||||||
|
ClassTemplate Holder
|
||||||
|
TemplateTypeParameter _
|
||||||
|
VarDecl static_var
|
||||||
|
TypeRef enum ns::VarType
|
||||||
|
CStyleCastExpr
|
||||||
|
TypeRef enum ns::VarType
|
||||||
|
IntegerLiteral
|
||||||
|
VarDecl static_var
|
||||||
|
TemplateTypeParameter _
|
||||||
|
TypeRef enum ns::VarType
|
||||||
|
TemplateRef Holder
|
||||||
|
TypeRef _
|
||||||
|
VarDecl Foo
|
||||||
|
UnexposedExpr static_var
|
||||||
|
UnexposedExpr static_var
|
||||||
|
DeclRefExpr static_var
|
||||||
|
TemplateRef Holder
|
||||||
|
VarDecl static_var
|
||||||
|
TypeRef enum ns::VarType
|
||||||
|
TemplateRef Holder
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@E@VarType",
|
||||||
|
"short_name": "VarType",
|
||||||
|
"qualified_name": "ns::VarType",
|
||||||
|
"definition": "1:2:8",
|
||||||
|
"uses": ["*1:2:8", "*1:6:22", "1:6:44", "*1:10:18"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@N@ns@ST>1#T@Holder",
|
||||||
|
"short_name": "Holder",
|
||||||
|
"qualified_name": "ns::Holder",
|
||||||
|
"definition": "1:5:10",
|
||||||
|
"vars": [0],
|
||||||
|
"uses": ["*1:5:10", "*1:10:26", "1:13:13", "1:14:14"]
|
||||||
|
}],
|
||||||
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@ST>1#T@Holder@static_var",
|
||||||
|
"short_name": "static_var",
|
||||||
|
"qualified_name": "ns::Holder::static_var",
|
||||||
|
"declaration": "1:6:30",
|
||||||
|
"definition": "1:10:37",
|
||||||
|
"variable_type": 0,
|
||||||
|
"declaring_type": 1,
|
||||||
|
"uses": ["1:6:30", "1:10:37"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@N@ns@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "ns::Foo",
|
||||||
|
"definition": "1:13:7",
|
||||||
|
"uses": ["1:13:7"]
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"usr": "c:@N@ns@S@Holder>#I@static_var",
|
||||||
|
"short_name": "static_var",
|
||||||
|
"qualified_name": "static_var",
|
||||||
|
"definition": "1:10:37",
|
||||||
|
"variable_type": 0,
|
||||||
|
"declaring_type": 2,
|
||||||
|
"uses": ["1:13:26", "1:10:37", "1:14:27"]
|
||||||
|
}, {
|
||||||
|
"id": 3,
|
||||||
|
"usr": "c:@N@ns@Foo2",
|
||||||
|
"short_name": "Foo2",
|
||||||
|
"qualified_name": "ns::Foo2",
|
||||||
|
"definition": "1:14:7",
|
||||||
|
"uses": ["1:14:7"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#include <string>
|
||||||
|
//#include <xiosbase>
|
||||||
|
|
||||||
|
//#include <sstream>
|
||||||
|
//#include <algorithm>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <string>
|
||||||
|
//#include <cstddef>
|
||||||
|
//#include <sstream>
|
||||||
|
//#include <iomanip>
|
||||||
|
//#include <limits>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <cstddef>
|
||||||
|
//#include <tuple>
|
||||||
|
//#include <type_traits>
|
||||||
|
//#include <string>
|
||||||
|
//#include <string>
|
||||||
|
//#include <type_traits>
|
||||||
|
//#include <iterator>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <string>
|
||||||
|
//#include <stdlib.h>
|
||||||
|
//#include <string>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <string>
|
||||||
|
//#include <cstddef>
|
||||||
|
//#include <cmath>
|
||||||
|
//#include <limits>
|
||||||
|
//#include <type_traits>
|
||||||
|
//#include <set>
|
||||||
|
//#include <string>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <iosfwd>
|
||||||
|
//#include <streambuf>
|
||||||
|
//#include <ostream>
|
||||||
|
//#include <fstream>
|
||||||
|
//#include <memory>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <string>
|
||||||
|
//#include <stdexcept>
|
||||||
|
//#include <string>
|
||||||
|
//#include <vector>
|
||||||
|
//#include <sstream>
|
||||||
|
//#include <algorithm>
|
@ -0,0 +1,51 @@
|
|||||||
|
namespace ns {
|
||||||
|
template<typename T>
|
||||||
|
struct Foo {
|
||||||
|
template<typename R>
|
||||||
|
static int foo() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int a = Foo<int>::foo<float>();
|
||||||
|
int b = Foo<bool>::foo<double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "ns::Foo",
|
||||||
|
"definition": "1:3:10",
|
||||||
|
"funcs": [0],
|
||||||
|
"uses": ["*1:3:10", "1:10:11", "1:11:11"]
|
||||||
|
}],
|
||||||
|
"functions": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@ST>1#T@Foo@FT@>1#Tfoo#I#S",
|
||||||
|
"short_name": "foo",
|
||||||
|
"qualified_name": "ns::Foo::foo",
|
||||||
|
"definition": "1:5:16",
|
||||||
|
"declaring_type": 0,
|
||||||
|
"uses": ["1:5:16", "1:10:21", "1:11:22"]
|
||||||
|
}],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "ns::a",
|
||||||
|
"definition": "1:10:7",
|
||||||
|
"uses": ["1:10:7"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@N@ns@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "ns::b",
|
||||||
|
"definition": "1:11:7",
|
||||||
|
"uses": ["1:11:7"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,39 @@
|
|||||||
|
namespace ns {
|
||||||
|
template<typename T>
|
||||||
|
class Foo {};
|
||||||
|
|
||||||
|
Foo<int> a;
|
||||||
|
Foo<bool> b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "ns::Foo",
|
||||||
|
"definition": "1:3:9",
|
||||||
|
"uses": ["*1:3:9", "*1:5:3", "*1:6:3"]
|
||||||
|
}],
|
||||||
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@N@ns@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "ns::a",
|
||||||
|
"definition": "1:5:12",
|
||||||
|
"variable_type": 0,
|
||||||
|
"uses": ["1:5:12"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@N@ns@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "ns::b",
|
||||||
|
"definition": "1:6:13",
|
||||||
|
"variable_type": 0,
|
||||||
|
"uses": ["1:6:13"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
48
tests/templates/template_class_func_usage_folded_into_one.cc
Normal file
48
tests/templates/template_class_func_usage_folded_into_one.cc
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
template<typename T>
|
||||||
|
struct Foo {
|
||||||
|
static int foo() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int a = Foo<int>::foo();
|
||||||
|
int b = Foo<bool>::foo();
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "Foo",
|
||||||
|
"definition": "1:2:8",
|
||||||
|
"funcs": [0],
|
||||||
|
"uses": ["*1:2:8", "1:8:9", "1:9:9"]
|
||||||
|
}],
|
||||||
|
"functions": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo@F@foo#S",
|
||||||
|
"short_name": "foo",
|
||||||
|
"qualified_name": "Foo::foo",
|
||||||
|
"definition": "1:3:14",
|
||||||
|
"declaring_type": 0,
|
||||||
|
"uses": ["1:3:14", "1:8:19", "1:9:20"]
|
||||||
|
}],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:8:5",
|
||||||
|
"uses": ["1:8:5"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:9:5",
|
||||||
|
"uses": ["1:9:5"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,49 @@
|
|||||||
|
template<typename T>
|
||||||
|
struct Foo {
|
||||||
|
template<typename R>
|
||||||
|
static int foo() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int a = Foo<int>::foo<float>();
|
||||||
|
int b = Foo<bool>::foo<double>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "Foo",
|
||||||
|
"definition": "1:2:8",
|
||||||
|
"funcs": [0],
|
||||||
|
"uses": ["*1:2:8", "1:9:9", "1:10:9"]
|
||||||
|
}],
|
||||||
|
"functions": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo@FT@>1#Tfoo#I#S",
|
||||||
|
"short_name": "foo",
|
||||||
|
"qualified_name": "Foo::foo",
|
||||||
|
"definition": "1:4:14",
|
||||||
|
"declaring_type": 0,
|
||||||
|
"uses": ["1:4:14", "1:9:19", "1:10:20"]
|
||||||
|
}],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:9:5",
|
||||||
|
"uses": ["1:9:5"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:10:5",
|
||||||
|
"uses": ["1:10:5"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
81
tests/templates/template_class_type_usage_folded_into_one.cc
Normal file
81
tests/templates/template_class_type_usage_folded_into_one.cc
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
enum A {};
|
||||||
|
enum B {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Foo {
|
||||||
|
struct Inner {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Foo<A>::Inner a;
|
||||||
|
Foo<B>::Inner b;
|
||||||
|
|
||||||
|
#if false
|
||||||
|
EnumDecl A
|
||||||
|
EnumDecl B
|
||||||
|
ClassTemplate Foo
|
||||||
|
TemplateTypeParameter T
|
||||||
|
StructDecl Inner
|
||||||
|
VarDecl a
|
||||||
|
TemplateRef Foo
|
||||||
|
TypeRef enum A
|
||||||
|
TypeRef struct Foo<enum A>::Inner
|
||||||
|
CallExpr Inner
|
||||||
|
VarDecl b
|
||||||
|
TemplateRef Foo
|
||||||
|
TypeRef enum B
|
||||||
|
TypeRef struct Foo<enum B>::Inner
|
||||||
|
CallExpr Inner
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@E@A",
|
||||||
|
"short_name": "A",
|
||||||
|
"qualified_name": "A",
|
||||||
|
"definition": "1:1:6",
|
||||||
|
"uses": ["*1:1:6", "*1:9:5"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@E@B",
|
||||||
|
"short_name": "B",
|
||||||
|
"qualified_name": "B",
|
||||||
|
"definition": "1:2:6",
|
||||||
|
"uses": ["*1:2:6", "*1:10:5"]
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"usr": "c:@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "Foo",
|
||||||
|
"definition": "1:5:8",
|
||||||
|
"uses": ["*1:5:8", "*1:9:1", "*1:10:1"]
|
||||||
|
}, {
|
||||||
|
"id": 3,
|
||||||
|
"usr": "c:@ST>1#T@Foo@S@Inner",
|
||||||
|
"short_name": "Inner",
|
||||||
|
"qualified_name": "Foo::Inner",
|
||||||
|
"definition": "1:6:10",
|
||||||
|
"uses": ["*1:6:10", "*1:9:9", "*1:10:9"]
|
||||||
|
}],
|
||||||
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:9:15",
|
||||||
|
"variable_type": 3,
|
||||||
|
"uses": ["1:9:15"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:10:15",
|
||||||
|
"variable_type": 3,
|
||||||
|
"uses": ["1:10:15"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
44
tests/templates/template_class_var_usage_folded_into_one.cc
Normal file
44
tests/templates/template_class_var_usage_folded_into_one.cc
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
template<typename T>
|
||||||
|
struct Foo {
|
||||||
|
static constexpr int var = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
int a = Foo<int>::var;
|
||||||
|
int b = Foo<bool>::var;
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "Foo",
|
||||||
|
"definition": "1:2:8",
|
||||||
|
"uses": ["*1:2:8", "1:6:9", "1:7:9"]
|
||||||
|
}],
|
||||||
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo@var",
|
||||||
|
"short_name": "var",
|
||||||
|
"qualified_name": "Foo::var",
|
||||||
|
"declaration": "1:3:24",
|
||||||
|
"uses": ["1:3:24", "1:6:19", "1:7:20"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:6:5",
|
||||||
|
"uses": ["1:6:5"]
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:7:5",
|
||||||
|
"uses": ["1:7:5"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
40
tests/templates/template_func_usage_folded_into_one.cc
Normal file
40
tests/templates/template_func_usage_folded_into_one.cc
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
template<typename T>
|
||||||
|
static int foo() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int a = foo<int>();
|
||||||
|
int b = foo<bool>();
|
||||||
|
|
||||||
|
// TODO: put template foo inside a namespace
|
||||||
|
// TODO: put template foo inside a template class inside a namespace
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [],
|
||||||
|
"functions": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:template_func_usage_folded_into_one.cc@FT@>1#Tfoo#I#",
|
||||||
|
"short_name": "foo",
|
||||||
|
"qualified_name": "foo",
|
||||||
|
"definition": "1:2:12",
|
||||||
|
"uses": ["1:2:12", "1:6:9", "1:7:9"]
|
||||||
|
}],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:6:5",
|
||||||
|
"uses": ["1:6:5"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:7:5",
|
||||||
|
"uses": ["1:7:5"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
37
tests/templates/template_type_usage_folded_into_one.cc
Normal file
37
tests/templates/template_type_usage_folded_into_one.cc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
template<typename T>
|
||||||
|
class Foo {};
|
||||||
|
|
||||||
|
Foo<int> a;
|
||||||
|
Foo<bool> b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "Foo",
|
||||||
|
"definition": "1:2:7",
|
||||||
|
"uses": ["*1:2:7", "*1:4:1", "*1:5:1"]
|
||||||
|
}],
|
||||||
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:4:10",
|
||||||
|
"variable_type": 0,
|
||||||
|
"uses": ["1:4:10"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:5:11",
|
||||||
|
"variable_type": 0,
|
||||||
|
"uses": ["1:5:11"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
73
tests/templates/template_var_usage_folded_into_one.cc
Normal file
73
tests/templates/template_var_usage_folded_into_one.cc
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
enum A {};
|
||||||
|
enum B {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T var = 3;
|
||||||
|
|
||||||
|
int a = var<A>;
|
||||||
|
int b = var<B>;
|
||||||
|
|
||||||
|
// TODO: No usages of types on var.
|
||||||
|
// libclang doesn't expose the info. File a bug.
|
||||||
|
|
||||||
|
#if false
|
||||||
|
EnumDecl A
|
||||||
|
EnumDecl B
|
||||||
|
UnexposedDecl var
|
||||||
|
VarDecl a
|
||||||
|
UnexposedExpr var
|
||||||
|
UnexposedExpr var
|
||||||
|
DeclRefExpr var
|
||||||
|
TypeRef enum A
|
||||||
|
UnexposedDecl var
|
||||||
|
VarDecl b
|
||||||
|
UnexposedExpr var
|
||||||
|
UnexposedExpr var
|
||||||
|
DeclRefExpr var
|
||||||
|
TypeRef enum B
|
||||||
|
UnexposedDecl var
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
OUTPUT:
|
||||||
|
{
|
||||||
|
"types": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@E@A",
|
||||||
|
"short_name": "A",
|
||||||
|
"qualified_name": "A",
|
||||||
|
"definition": "1:1:6",
|
||||||
|
"uses": ["*1:1:6", "1:7:13"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@E@B",
|
||||||
|
"short_name": "B",
|
||||||
|
"qualified_name": "B",
|
||||||
|
"definition": "1:2:6",
|
||||||
|
"uses": ["*1:2:6", "1:8:13"]
|
||||||
|
}],
|
||||||
|
"functions": [],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@var",
|
||||||
|
"short_name": "var",
|
||||||
|
"qualified_name": "var",
|
||||||
|
"definition": "1:5:3",
|
||||||
|
"uses": ["1:5:3"]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@a",
|
||||||
|
"short_name": "a",
|
||||||
|
"qualified_name": "a",
|
||||||
|
"definition": "1:7:5",
|
||||||
|
"uses": ["1:7:5"]
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"usr": "c:@b",
|
||||||
|
"short_name": "b",
|
||||||
|
"qualified_name": "b",
|
||||||
|
"definition": "1:8:5",
|
||||||
|
"uses": ["1:8:5"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user