mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-26 17:41:58 +00:00
Re-pick "Handle template <class T> class A" but does not assign names to templates without body
This commit is contained in:
parent
7f9f6e0c6b
commit
7aea052f09
@ -774,11 +774,13 @@ bool IsTypeDefinition(const CXIdxContainerInfo* container) {
|
|||||||
|
|
||||||
struct VisitDeclForTypeUsageParam {
|
struct VisitDeclForTypeUsageParam {
|
||||||
IndexFile* db;
|
IndexFile* db;
|
||||||
|
optional<IndexTypeId> toplevel_type;
|
||||||
int has_processed_any = false;
|
int has_processed_any = false;
|
||||||
optional<ClangCursor> previous_cursor;
|
optional<ClangCursor> previous_cursor;
|
||||||
optional<IndexTypeId> initial_type;
|
optional<IndexTypeId> initial_type;
|
||||||
|
|
||||||
VisitDeclForTypeUsageParam(IndexFile* db) : db(db) {}
|
VisitDeclForTypeUsageParam(IndexFile* db, optional<IndexTypeId> toplevel_type)
|
||||||
|
: db(db), toplevel_type(toplevel_type) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void VisitDeclForTypeUsageVisitorHandler(ClangCursor cursor,
|
void VisitDeclForTypeUsageVisitorHandler(ClangCursor cursor,
|
||||||
@ -786,6 +788,29 @@ void VisitDeclForTypeUsageVisitorHandler(ClangCursor cursor,
|
|||||||
param->has_processed_any = true;
|
param->has_processed_any = true;
|
||||||
IndexFile* db = param->db;
|
IndexFile* db = param->db;
|
||||||
|
|
||||||
|
// For |A<int> a| where there is a specialization for |A<int>|,
|
||||||
|
// the |referenced_usr| below resolves to the primary template and
|
||||||
|
// attributes the use to the primary template instead of the specialization.
|
||||||
|
// |toplevel_type| is retrieved |clang_getCursorType| which can be a specialization.
|
||||||
|
// If its name is the same as the primary template's, we assume the use
|
||||||
|
// should be attributed to the specialization.
|
||||||
|
// This heuristic fails when a member class bears the same name with its container.
|
||||||
|
//
|
||||||
|
// template<class T>
|
||||||
|
// struct C { struct C {}; };
|
||||||
|
// C<int>::C a;
|
||||||
|
//
|
||||||
|
// We will attribute |::C| to the parent class.
|
||||||
|
if (param->toplevel_type) {
|
||||||
|
IndexType* ref_type = db->Resolve(*param->toplevel_type);
|
||||||
|
std::string name = cursor.get_referenced().get_spelling();
|
||||||
|
if (name == ref_type->def.short_name) {
|
||||||
|
UniqueAdd(ref_type->uses, cursor.get_spelling_range());
|
||||||
|
param->toplevel_type = nullopt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string referenced_usr =
|
std::string referenced_usr =
|
||||||
cursor.get_referenced().template_specialization_to_template_definition().get_usr();
|
cursor.get_referenced().template_specialization_to_template_definition().get_usr();
|
||||||
// TODO: things in STL cause this to be empty. Figure out why and document it.
|
// TODO: things in STL cause this to be empty. Figure out why and document it.
|
||||||
@ -846,9 +871,15 @@ ClangCursor::VisitResult VisitDeclForTypeUsageVisitor(
|
|||||||
// useful if trying to figure out ie, what a using statement refers to. If
|
// useful if trying to figure out ie, what a using statement refers to. If
|
||||||
// trying to generally resolve a cursor to a type, use
|
// trying to generally resolve a cursor to a type, use
|
||||||
// ResolveToDeclarationType, which works in more scenarios.
|
// ResolveToDeclarationType, which works in more scenarios.
|
||||||
|
// If |decl_cursor| is a variable of a template type, clang_getCursorType
|
||||||
|
// may return a specialized template which is preciser than the primary
|
||||||
|
// template.
|
||||||
|
// We use |toplevel_type| to attribute the use to the specialized template
|
||||||
|
// instead of the primary template.
|
||||||
optional<IndexTypeId> AddDeclTypeUsages(
|
optional<IndexTypeId> AddDeclTypeUsages(
|
||||||
IndexFile* db,
|
IndexFile* db,
|
||||||
ClangCursor decl_cursor,
|
ClangCursor decl_cursor,
|
||||||
|
optional<IndexTypeId> toplevel_type,
|
||||||
const CXIdxContainerInfo* semantic_container,
|
const CXIdxContainerInfo* semantic_container,
|
||||||
const CXIdxContainerInfo* lexical_container) {
|
const CXIdxContainerInfo* lexical_container) {
|
||||||
//
|
//
|
||||||
@ -948,7 +979,7 @@ optional<IndexTypeId> AddDeclTypeUsages(
|
|||||||
process_last_type_ref = false;
|
process_last_type_ref = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VisitDeclForTypeUsageParam param(db);
|
VisitDeclForTypeUsageParam param(db, toplevel_type);
|
||||||
decl_cursor.VisitChildren(&VisitDeclForTypeUsageVisitor, ¶m);
|
decl_cursor.VisitChildren(&VisitDeclForTypeUsageVisitor, ¶m);
|
||||||
|
|
||||||
// VisitDeclForTypeUsageVisitor guarantees that if there are multiple TypeRef
|
// VisitDeclForTypeUsageVisitor guarantees that if there are multiple TypeRef
|
||||||
@ -1374,8 +1405,8 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// 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.
|
||||||
// TODO: See if we can remove this function call.
|
// TODO: See if we can remove this function call.
|
||||||
AddDeclTypeUsages(db, decl_cursor, decl->semanticContainer,
|
AddDeclTypeUsages(db, decl_cursor, var->def.variable_type,
|
||||||
decl->lexicalContainer);
|
decl->semanticContainer, decl->lexicalContainer);
|
||||||
|
|
||||||
// We don't need to assign declaring type multiple times if this variable
|
// We don't need to assign declaring type multiple times if this variable
|
||||||
// has already been seen.
|
// has already been seen.
|
||||||
@ -1416,7 +1447,7 @@ void OnIndexDeclaration(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.
|
||||||
AddDeclTypeUsages(db, decl_cursor, decl->semanticContainer,
|
AddDeclTypeUsages(db, decl_cursor, nullopt, decl->semanticContainer,
|
||||||
decl->lexicalContainer);
|
decl->lexicalContainer);
|
||||||
|
|
||||||
// Add definition or declaration. This is a bit tricky because we treat
|
// Add definition or declaration. This is a bit tricky because we treat
|
||||||
@ -1543,8 +1574,9 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// Note we want to fetch the first TypeRef. Running
|
// Note we want to fetch the first TypeRef. Running
|
||||||
// ResolveCursorType(decl->cursor) would return
|
// ResolveCursorType(decl->cursor) would return
|
||||||
// the type of the typedef/using, not the type of the referenced type.
|
// the type of the typedef/using, not the type of the referenced type.
|
||||||
optional<IndexTypeId> alias_of = AddDeclTypeUsages(
|
optional<IndexTypeId> alias_of =
|
||||||
db, decl->cursor, decl->semanticContainer, decl->lexicalContainer);
|
AddDeclTypeUsages(db, decl->cursor, nullopt, decl->semanticContainer,
|
||||||
|
decl->lexicalContainer);
|
||||||
|
|
||||||
IndexTypeId type_id = db->ToTypeId(HashUsr(decl->entityInfo->USR));
|
IndexTypeId type_id = db->ToTypeId(HashUsr(decl->entityInfo->USR));
|
||||||
IndexType* type = db->Resolve(type_id);
|
IndexType* type = db->Resolve(type_id);
|
||||||
@ -1659,8 +1691,8 @@ void OnIndexDeclaration(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];
|
||||||
|
|
||||||
AddDeclTypeUsages(db, base_class->cursor, decl->semanticContainer,
|
AddDeclTypeUsages(db, base_class->cursor, nullopt,
|
||||||
decl->lexicalContainer);
|
decl->semanticContainer, decl->lexicalContainer);
|
||||||
optional<IndexTypeId> parent_type_id =
|
optional<IndexTypeId> parent_type_id =
|
||||||
ResolveToDeclarationType(db, base_class->cursor);
|
ResolveToDeclarationType(db, base_class->cursor);
|
||||||
// type_def ptr could be invalidated by ResolveToDeclarationType and
|
// type_def ptr could be invalidated by ResolveToDeclarationType and
|
||||||
@ -1888,7 +1920,21 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
|
|||||||
case CXIdxEntity_CXXClass: {
|
case CXIdxEntity_CXXClass: {
|
||||||
ClangCursor ref_cursor = ref->referencedEntity->cursor;
|
ClangCursor ref_cursor = ref->referencedEntity->cursor;
|
||||||
ref_cursor = ref_cursor.template_specialization_to_template_definition();
|
ref_cursor = ref_cursor.template_specialization_to_template_definition();
|
||||||
IndexType* referenced = db->Resolve(db->ToTypeId(ref_cursor.get_usr_hash()));
|
IndexType* ref_type = db->Resolve(db->ToTypeId(ref_cursor.get_usr_hash()));
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// This example is handled by OnIndexReference, not OnIndexDeclaration,
|
||||||
|
// and it does not have |short_name|.
|
||||||
|
//
|
||||||
|
// template <class T> class A;
|
||||||
|
//if (ref_type->def.short_name.empty()) {
|
||||||
|
// ref_type->def.short_name = ref->referencedEntity->name;
|
||||||
|
// ref_type->def.detailed_name = ref->referencedEntity->name;
|
||||||
|
// if (!ref_type->def.definition_spelling) {
|
||||||
|
// ref_type->def.definition_spelling = ref_cursor.get_spelling_range();
|
||||||
|
// ref_type->def.definition_extent = ref_cursor.get_extent();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
//
|
//
|
||||||
// The following will generate two TypeRefs to Foo, both located at the
|
// The following will generate two TypeRefs to Foo, both located at the
|
||||||
@ -1905,7 +1951,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
|
|||||||
// Foo f;
|
// Foo f;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
UniqueAdd(referenced->uses,
|
UniqueAdd(ref_type->uses,
|
||||||
ClangCursor(ref->cursor).get_spelling_range());
|
ClangCursor(ref->cursor).get_spelling_range());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -515,16 +515,18 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
|||||||
//
|
//
|
||||||
// Then order functions before other types, which makes goto definition work
|
// Then order functions before other types, which makes goto definition work
|
||||||
// better on constructors.
|
// better on constructors.
|
||||||
std::sort(symbols.begin(), symbols.end(),
|
std::sort(symbols.begin(), symbols.end(), [](const SymbolRef& a,
|
||||||
[](const SymbolRef& a, const SymbolRef& b) {
|
const SymbolRef& b) {
|
||||||
int a_size = ComputeRangeSize(a.loc.range);
|
int a_size = ComputeRangeSize(a.loc.range);
|
||||||
int b_size = ComputeRangeSize(b.loc.range);
|
int b_size = ComputeRangeSize(b.loc.range);
|
||||||
|
|
||||||
if (a_size != b_size)
|
if (a_size != b_size)
|
||||||
return a_size < b_size;
|
return a_size < b_size;
|
||||||
// operator> orders Var/Func in front of orders.
|
// operator> orders Var/Func before Type.
|
||||||
return static_cast<int>(a.idx.kind) >
|
int t = static_cast<int>(a.idx.kind) - static_cast<int>(b.idx.kind);
|
||||||
static_cast<int>(b.idx.kind);
|
if (t)
|
||||||
|
return t > 0;
|
||||||
|
return a.idx.idx < b.idx.idx;
|
||||||
});
|
});
|
||||||
|
|
||||||
return symbols;
|
return symbols;
|
||||||
|
Loading…
Reference in New Issue
Block a user