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
|
||||
// \n will implicitly write \r\n. Language server API will ignore a
|
||||
// \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;
|
||||
IndexedFile* db = param->db;
|
||||
|
||||
// TODO: Something in STL (type_traits)? reports an empty USR.
|
||||
std::string referenced_usr = cursor.get_referenced().get_usr();
|
||||
if (referenced_usr == "")
|
||||
return;
|
||||
|
||||
std::string referenced_usr = cursor.get_referenced().template_specialization_to_template_definition().get_usr();
|
||||
TypeId ref_type_id = db->ToTypeId(referenced_usr);
|
||||
|
||||
if (!param->initial_type)
|
||||
param->initial_type = ref_type_id;
|
||||
|
||||
@ -392,7 +389,23 @@ clang::VisiterResult VisitDeclForTypeUsageVisitor(clang::Cursor cursor, clang::C
|
||||
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,
|
||||
const CXIdxContainerInfo* lexical_container) {
|
||||
//
|
||||
@ -415,7 +428,46 @@ optional<TypeId> ResolveDeclToType(IndexedFile* db, clang::Cursor decl_cursor,
|
||||
// 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
|
||||
// out-of-line w.r.t. the parent type.
|
||||
//
|
||||
@ -449,7 +501,12 @@ optional<TypeId> ResolveDeclToType(IndexedFile* db, clang::Cursor decl_cursor,
|
||||
else {
|
||||
// If we are not processing the last type ref, it *must* be a TypeRef (ie,
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -496,12 +553,15 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
var_def->def.declaration = 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
|
||||
// interesting reference for parameter declarations - that is handled when
|
||||
// the function declaration is encountered since we won't receive ParmDecl
|
||||
// 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())
|
||||
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
|
||||
// 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());
|
||||
//if (ret_type.resolved_type)
|
||||
@ -592,7 +652,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
case CXCursor_ParmDecl:
|
||||
// We don't need to know the arg type, but we do want to mark it as
|
||||
// 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());
|
||||
//if (arg_type.resolved_type)
|
||||
@ -639,7 +699,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
case CXIdxEntity_Typedef:
|
||||
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);
|
||||
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) {
|
||||
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.
|
||||
if (parent_type_id) {
|
||||
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_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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -805,9 +872,13 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re
|
||||
Location our_loc = db->id_cache.Resolve(ref->loc, true /*is_interesting*/);
|
||||
if (!parent_loc.IsEqualTo(our_loc)) {
|
||||
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());
|
||||
IndexedTypeDef* type_def = db->Resolve(called_def->def.declaring_type.value());
|
||||
type_def->AddUsage(our_loc);
|
||||
//}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -820,7 +891,10 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re
|
||||
case CXIdxEntity_Struct:
|
||||
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);
|
||||
|
||||
// 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;
|
||||
IndexParam param(&db, &ns);
|
||||
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);
|
||||
|
||||
|
@ -27,6 +27,10 @@ bool Type::is_fundamental() const {
|
||||
cx_type.kind <= CXType_LastBuiltin;
|
||||
}
|
||||
|
||||
CXCursor Type::get_declaration() const {
|
||||
return clang_getTypeDeclaration(cx_type);
|
||||
}
|
||||
|
||||
std::string Type::get_usr() const {
|
||||
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 {
|
||||
// TODO: Should we return this same cursor if this is not a template? We
|
||||
// can probably check USR to do that.
|
||||
return clang_getSpecializedCursorTemplate(cx_cursor);
|
||||
CXCursor definition = clang_getSpecializedCursorTemplate(cx_cursor);
|
||||
if (definition.kind == CXCursor_FirstInvalid)
|
||||
return cx_cursor;
|
||||
return definition;
|
||||
}
|
||||
|
||||
Cursor Cursor::get_referenced() const {
|
||||
|
@ -21,6 +21,8 @@ public:
|
||||
// Returns true if this is a fundamental type like int.
|
||||
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_spelling() const;
|
||||
|
||||
@ -58,7 +60,14 @@ public:
|
||||
|
||||
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 get_referenced() const;
|
||||
Cursor get_canonical() 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
|
||||
|
||||
/*
|
||||
@ -94,8 +94,12 @@ int main222(int argc, char** argv) {
|
||||
*/
|
||||
|
||||
for (std::string path : GetFilesInFolder("tests", true /*add_folder_to_path*/)) {
|
||||
//if (path != "tests/usage/type_usage_declare_field.cc") continue;
|
||||
path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
||||
//if (path == "tests/foobar.cc") continue;
|
||||
//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.
|
||||
std::string expected_output;
|
||||
@ -105,7 +109,7 @@ int main222(int argc, char** argv) {
|
||||
|
||||
// Run test.
|
||||
std::cout << "[START] " << path << std::endl;
|
||||
IndexedFile db = Parse(path, {}, true /*dump_ast*/);
|
||||
IndexedFile db = Parse(path, {}, false /*dump_ast*/);
|
||||
VerifySerializeToFrom(&db);
|
||||
std::string actual_output = db.ToString();
|
||||
|
||||
|
@ -22,6 +22,7 @@ OUTPUT:
|
||||
"short_name": "A",
|
||||
"qualified_name": "Foo::A",
|
||||
"definition": "1:2:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:2:3"]
|
||||
}, {
|
||||
@ -30,6 +31,7 @@ OUTPUT:
|
||||
"short_name": "B",
|
||||
"qualified_name": "Foo::B",
|
||||
"definition": "1:3:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:3:3"]
|
||||
}]
|
||||
|
@ -22,6 +22,7 @@ OUTPUT:
|
||||
"short_name": "A",
|
||||
"qualified_name": "Foo::A",
|
||||
"definition": "1:2:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:2:3"]
|
||||
}, {
|
||||
@ -30,6 +31,7 @@ OUTPUT:
|
||||
"short_name": "B",
|
||||
"qualified_name": "Foo::B",
|
||||
"definition": "1:3:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:3:3"]
|
||||
}]
|
||||
|
@ -22,6 +22,7 @@ OUTPUT:
|
||||
"short_name": "A",
|
||||
"qualified_name": "Foo::A",
|
||||
"definition": "1:2:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:2:3"]
|
||||
}, {
|
||||
@ -30,6 +31,7 @@ OUTPUT:
|
||||
"short_name": "B",
|
||||
"qualified_name": "Foo::B",
|
||||
"definition": "1:3:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:3:3"]
|
||||
}]
|
||||
|
@ -24,6 +24,7 @@ OUTPUT:
|
||||
"short_name": "A",
|
||||
"qualified_name": "Foo::A",
|
||||
"definition": "1:2:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"uses": ["1:2:3", "1:6:14"]
|
||||
}, {
|
||||
@ -32,6 +33,7 @@ OUTPUT:
|
||||
"short_name": "B",
|
||||
"qualified_name": "Foo::B",
|
||||
"definition": "1:3:3",
|
||||
"variable_type": 0,
|
||||
"declaring_type": 0,
|
||||
"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:
|
||||
{
|
||||
"types": [],
|
||||
"functions": [{
|
||||
"types": [{
|
||||
"id": 0,
|
||||
"usr": "c:@F@called#I#",
|
||||
"short_name": "called",
|
||||
"qualified_name": "called",
|
||||
"declarations": ["1:1:6"],
|
||||
"callers": ["2@1:6:3"],
|
||||
"uses": ["1:1:6", "1:6:3"]
|
||||
"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:@F@gen#",
|
||||
"short_name": "gen",
|
||||
"qualified_name": "gen",
|
||||
"definition": "1:3:5",
|
||||
"callers": ["2@1:6:10", "2@1:6:18"],
|
||||
"uses": ["1:3:5", "1:6:10", "1:6:18"]
|
||||
"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:@F@foo#",
|
||||
"short_name": "foo",
|
||||
"qualified_name": "foo",
|
||||
"definition": "1:5:6",
|
||||
"callees": ["0@1:6:3", "1@1:6:10", "1@1:6:18"],
|
||||
"uses": ["1:5:6"]
|
||||
"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"]
|
||||
}],
|
||||
"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