Browse Source

better specialized function definition indexing

pull/2/head
Jacob Dufault 8 years ago
parent
commit
f7e2b20059
  1. 180
      indexer.cpp
  2. 3
      test.cc
  3. 39
      tests/templates/specialized_func_definition.cc

180
indexer.cpp

@ -540,15 +540,16 @@ optional<TypeId> AddDeclUsages(IndexedFile* db, clang::Cursor decl_cursor,
VisitDeclForTypeUsageVisitorHandler(param.previous_cursor.value(), &param);
}
else {
// If we are not processing the last type ref, it *must* be a TypeRef (ie,
// and not a TemplateRef).
// If we are not processing the last type ref, it *must* be a TypeRef or
// TemplateRef.
//
// 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 ||
param.previous_cursor.value().get_kind() == CXCursor_TemplateRef));
}
return param.initial_type;
@ -632,105 +633,114 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
case CXIdxEntity_CXXConversionFunction:
{
clang::Cursor decl_cursor = decl->cursor;
FuncId func_id = db->ToFuncId(decl->entityInfo->USR);
IndexedFuncDef* func_def = db->Resolve(func_id);
func_def->is_bad_def = is_system_def;
clang::Cursor resolved = decl_cursor.template_specialization_to_template_definition();
// TODO: Eventually run with this if. Right now I want to iron out bugs this may shadow.
//if (!decl->isRedeclaration) {
func_def->def.short_name = decl->entityInfo->name;
func_def->def.qualified_name = ns->QualifiedName(decl->semanticContainer, func_def->def.short_name);
//}
FuncId func_id = db->ToFuncId(resolved.cx_cursor);
IndexedFuncDef* func_def = db->Resolve(func_id);
Location decl_loc = db->id_cache.Resolve(decl->loc, false /*interesting*/);
if (decl->isDefinition)
func_def->uses.push_back(decl_loc);
// We don't actually need to know the return type, but we need to mark it
// as an interesting usage.
AddDeclUsages(db, decl_cursor, true /*is_interesting*/, decl->semanticContainer, decl->lexicalContainer);
// TODO: support multiple definitions per function; right now we are hacking the 'declarations' field by
// adding a definition when we really don't have one.
if (decl->isDefinition && !func_def->def.definition.has_value())
func_def->def.definition = decl_loc;
else
func_def->declarations.push_back(decl_loc);
func_def->uses.push_back(decl_loc);
bool is_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor);
bool is_ctor_or_dtor = decl->entityInfo->kind == CXIdxEntity_CXXConstructor || decl->entityInfo->kind == CXIdxEntity_CXXDestructor;
//bool process_declaring_type = is_pure_virtual || is_ctor_or_dtor;
// Add function usage information. We only want to do it once per
// definition/declaration. Do it on definition since there should only ever
// be one of those in the entire program.
if (IsTypeDefinition(decl->semanticContainer)) {
TypeId declaring_type_id = db->ToTypeId(decl->semanticContainer->cursor);
IndexedTypeDef* declaring_type_def = db->Resolve(declaring_type_id);
func_def->def.declaring_type = declaring_type_id;
// If decl_cursor != resolved, then decl_cursor is a template specialization. We
// don't want to override a lot of the function definition information in that
// scenario.
if (decl_cursor == resolved) {
func_def->is_bad_def = is_system_def;
// TODO: Eventually run with this if. Right now I want to iron out bugs this may shadow.
//if (!decl->isRedeclaration) {
func_def->def.short_name = decl->entityInfo->name;
func_def->def.qualified_name = ns->QualifiedName(decl->semanticContainer, func_def->def.short_name);
//}
bool is_pure_virtual = clang_CXXMethod_isPureVirtual(decl->cursor);
bool is_ctor_or_dtor = decl->entityInfo->kind == CXIdxEntity_CXXConstructor || decl->entityInfo->kind == CXIdxEntity_CXXDestructor;
//bool process_declaring_type = is_pure_virtual || is_ctor_or_dtor;
// Add function usage information. We only want to do it once per
// definition/declaration. Do it on definition since there should only ever
// be one of those in the entire program.
if (IsTypeDefinition(decl->semanticContainer)) {
TypeId declaring_type_id = db->ToTypeId(decl->semanticContainer->cursor);
IndexedTypeDef* declaring_type_def = db->Resolve(declaring_type_id);
func_def->def.declaring_type = declaring_type_id;
// Mark a type reference at the ctor/dtor location.
// TODO: Should it be interesting?
if (is_ctor_or_dtor) {
Location type_usage_loc = decl_loc;
declaring_type_def->AddUsage(type_usage_loc);
}
// Mark a type reference at the ctor/dtor location.
// TODO: Should it be interesting?
if (is_ctor_or_dtor) {
Location type_usage_loc = decl_loc;
declaring_type_def->AddUsage(type_usage_loc);
// Register function in declaring type if it hasn't been registered yet.
if (!Contains(declaring_type_def->def.funcs, func_id))
declaring_type_def->def.funcs.push_back(func_id);
}
// Register function in declaring type if it hasn't been registered yet.
if (!Contains(declaring_type_def->def.funcs, func_id))
declaring_type_def->def.funcs.push_back(func_id);
}
// We don't actually need to know the return type, but we need to mark it
// as an interesting usage.
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)
// AddInterestingUsageToType(db, ret_type, FindLocationOfTypeSpecifier(decl_cursor));
if (decl->isDefinition || is_pure_virtual) {
// Mark type usage for parameters as interesting. We handle this here
// instead of inside var declaration because clang will not emit a var
// declaration for an unnamed parameter, but we still want to mark the
// usage as interesting.
// TODO: Do a similar thing for function decl parameter usages. Mark
// prototype params as interesting type usages but also relate mark
// them as as usages on the primary variable - requires USR to be
// the same. We can work around it by declaring which variables a
// parameter has declared and update the USR in the definition.
clang::Cursor cursor = decl->cursor;
for (clang::Cursor arg : cursor.get_arguments()) {
switch (arg.get_kind()) {
case CXCursor_ParmDecl:
// We don't need to know the arg type, but we do want to mark it as
// an interesting usage. Note that we use semanticContainer twice
// because a parameter is not really part of the lexical container.
AddDeclUsages(db, arg, true /*is_interesting*/, decl->semanticContainer, decl->semanticContainer);
//TypeResolution arg_type = ResolveToType(db, arg.get_type());
//if (arg_type.resolved_type)
// AddInterestingUsageToType(db, arg_type, FindLocationOfTypeSpecifier(arg));
break;
//TypeResolution ret_type = ResolveToType(db, decl_cursor.get_type().get_return_type());
//if (ret_type.resolved_type)
// AddInterestingUsageToType(db, ret_type, FindLocationOfTypeSpecifier(decl_cursor));
if (decl->isDefinition || is_pure_virtual) {
// Mark type usage for parameters as interesting. We handle this here
// instead of inside var declaration because clang will not emit a var
// declaration for an unnamed parameter, but we still want to mark the
// usage as interesting.
// TODO: Do a similar thing for function decl parameter usages. Mark
// prototype params as interesting type usages but also relate mark
// them as as usages on the primary variable - requires USR to be
// the same. We can work around it by declaring which variables a
// parameter has declared and update the USR in the definition.
clang::Cursor cursor = decl->cursor;
for (clang::Cursor arg : cursor.get_arguments()) {
switch (arg.get_kind()) {
case CXCursor_ParmDecl:
// We don't need to know the arg type, but we do want to mark it as
// an interesting usage. Note that we use semanticContainer twice
// because a parameter is not really part of the lexical container.
AddDeclUsages(db, arg, true /*is_interesting*/, decl->semanticContainer, decl->semanticContainer);
//TypeResolution arg_type = ResolveToType(db, arg.get_type());
//if (arg_type.resolved_type)
// AddInterestingUsageToType(db, arg_type, FindLocationOfTypeSpecifier(arg));
break;
}
}
}
// Process inheritance.
//void clang_getOverriddenCursors(CXCursor cursor, CXCursor **overridden, unsigned *num_overridden);
//void clang_disposeOverriddenCursors(CXCursor *overridden);
if (clang_CXXMethod_isVirtual(decl->cursor)) {
CXCursor* overridden;
unsigned int num_overridden;
clang_getOverriddenCursors(decl->cursor, &overridden, &num_overridden);
// Process inheritance.
//void clang_getOverriddenCursors(CXCursor cursor, CXCursor **overridden, unsigned *num_overridden);
//void clang_disposeOverriddenCursors(CXCursor *overridden);
if (clang_CXXMethod_isVirtual(decl->cursor)) {
CXCursor* overridden;
unsigned int num_overridden;
clang_getOverriddenCursors(decl->cursor, &overridden, &num_overridden);
// TODO: How to handle multiple parent overrides??
for (unsigned int i = 0; i < num_overridden; ++i) {
clang::Cursor parent = overridden[i];
FuncId parent_id = db->ToFuncId(parent.get_usr());
IndexedFuncDef* parent_def = db->Resolve(parent_id);
func_def = db->Resolve(func_id); // ToFuncId invalidated func_def
// TODO: How to handle multiple parent overrides??
for (unsigned int i = 0; i < num_overridden; ++i) {
clang::Cursor parent = overridden[i];
FuncId parent_id = db->ToFuncId(parent.get_usr());
IndexedFuncDef* parent_def = db->Resolve(parent_id);
func_def = db->Resolve(func_id); // ToFuncId invalidated func_def
func_def->def.base = parent_id;
parent_def->derived.push_back(func_id);
}
func_def->def.base = parent_id;
parent_def->derived.push_back(func_id);
}
clang_disposeOverriddenCursors(overridden);
clang_disposeOverriddenCursors(overridden);
}
}
}

3
test.cc

@ -94,9 +94,10 @@ int main(int argc, char** argv) {
*/
for (std::string path : GetFilesInFolder("tests", true /*add_folder_to_path*/)) {
//if (path != "tests/templates/func_specialized_template_param.cc") continue;
//if (path != "tests/templates/specialized_func_definition.cc") continue;
//if (path != "tests/constructors/invalid_reference.cc") continue;
//if (path == "tests/inheritance/class_inherit_templated_parent.cc") continue;
//if (path != "tests/foobar.cc") continue;
if (path == "tests/stl.cc") continue;
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;

39
tests/templates/specialized_func_definition.cc

@ -0,0 +1,39 @@
template<class T>
class Template {
void Foo();
};
template<class T>
void Template<T>::Foo() {}
void Template<void>::Foo() {}
/*
// TODO: usage information on Template is bad.
// TODO: Foo() should have multiple definitions.
OUTPUT:
{
"types": [{
"id": 0,
"usr": "c:@ST>1#T@Template",
"short_name": "Template",
"qualified_name": "Template",
"definition": "1:2:7",
"funcs": [0],
"uses": ["*1:2:7", "*1:7:6", "1:9:6"]
}],
"functions": [{
"id": 0,
"usr": "c:@ST>1#T@Template@F@Foo#",
"short_name": "Foo",
"qualified_name": "Template::Foo",
"declarations": ["1:3:8", "1:9:22"],
"definition": "1:7:19",
"declaring_type": 0,
"uses": ["1:3:8", "1:7:19", "1:9:22"]
}],
"variables": []
}
*/
Loading…
Cancel
Save