From d87d74083caa18aa990f3f9e0ca60a3d72f45067 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Sun, 19 Feb 2017 16:56:56 -0800 Subject: [PATCH] wip-new-indexer --- libclangmm/Cursor.h | 2 +- libclangmm/SourceLocation.cc | 14 + libclangmm/SourceLocation.h | 11 +- main.cpp | 562 ++++++++++++++++-- tests/class_forward_declaration.cc | 4 +- tests/constructors/constructor.cc | 3 +- tests/constructors/destructor.cc | 5 + tests/foobar.cc | 43 ++ tests/function_declaration.cc | 2 +- tests/function_declaration_definition.cc | 4 +- tests/function_definition.cc | 3 +- tests/method_declaration.cc | 12 +- tests/method_definition.cc | 7 +- tests/method_inline_declaration.cc | 6 +- tests/namespaces/anonymous_function.cc | 2 +- tests/namespaces/function_declaration.cc | 2 +- tests/namespaces/function_definition.cc | 3 +- tests/namespaces/method_declaration.cc | 5 +- tests/namespaces/method_definition.cc | 9 +- tests/namespaces/method_inline_declaration.cc | 6 +- tests/usage/func_usage_addr_func.cc | 9 +- tests/usage/func_usage_addr_method.cc | 35 +- tests/usage/func_usage_call_func.cc | 5 +- tests/usage/func_usage_call_method.cc | 13 +- .../usage/func_usage_class_inline_var_def.cc | 13 +- tests/usage/func_usage_forward_decl_func.cc | 6 +- tests/usage/func_usage_forward_decl_method.cc | 13 +- tests/usage/func_usage_template_func.cc | 32 + tests/usage/type_usage_declare_extern.cc | 5 +- tests/usage/type_usage_on_return_type.cc | 4 + tests/usage/type_usage_various.cc | 52 ++ tests/vars/function_local.cc | 14 +- 32 files changed, 767 insertions(+), 139 deletions(-) create mode 100644 tests/foobar.cc create mode 100644 tests/usage/func_usage_template_func.cc create mode 100644 tests/usage/type_usage_various.cc diff --git a/libclangmm/Cursor.h b/libclangmm/Cursor.h index acd4c11c..cf75557a 100644 --- a/libclangmm/Cursor.h +++ b/libclangmm/Cursor.h @@ -44,7 +44,7 @@ enum class VisiterResult { class Cursor { public: Cursor(); - explicit Cursor(const CXCursor& other); + Cursor(const CXCursor& other); operator bool() const; bool operator==(const Cursor& rhs) const; diff --git a/libclangmm/SourceLocation.cc b/libclangmm/SourceLocation.cc index e460578a..5db101a8 100644 --- a/libclangmm/SourceLocation.cc +++ b/libclangmm/SourceLocation.cc @@ -17,6 +17,8 @@ SourceLocation::SourceLocation(CXTranslationUnit &tu, const std::string &filepat //cx_location = clang_getLocation(tu, file, line, column); } +SourceLocation::SourceLocation() {} + SourceLocation::SourceLocation(const CXSourceLocation& cx_location) { //clang_getExpansionLocation @@ -26,6 +28,18 @@ SourceLocation::SourceLocation(const CXSourceLocation& cx_location) { path = clang::ToString(clang_getFileName(file)); } +SourceLocation::SourceLocation(const CXIdxLoc& cx_location) + : SourceLocation(clang_indexLoc_getCXSourceLocation(cx_location)) { +} + +bool SourceLocation::operator==(const SourceLocation& o) { + return path == o.path && line == o.line && column == o.column; +} + +bool SourceLocation::operator!=(const SourceLocation& o) { + return !(*this == o); +} + std::string SourceLocation::ToString() const { return path + ":" + std::to_string(line) + ":" + std::to_string(column); } diff --git a/libclangmm/SourceLocation.h b/libclangmm/SourceLocation.h index 1d8ba129..54fd52c4 100644 --- a/libclangmm/SourceLocation.h +++ b/libclangmm/SourceLocation.h @@ -21,12 +21,17 @@ class SourceLocation { SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned offset); SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned line, unsigned column); public: + SourceLocation(); SourceLocation(const CXSourceLocation& cx_location); + SourceLocation(const CXIdxLoc& cx_location); + + bool operator==(const SourceLocation& o); + bool operator!=(const SourceLocation& o); std::string path; - unsigned line; - unsigned column; - unsigned offset; + unsigned line = 0; + unsigned column = 0; + unsigned offset = 0; std::string ToString() const; }; diff --git a/main.cpp b/main.cpp index c4df6ff8..eeb83999 100644 --- a/main.cpp +++ b/main.cpp @@ -18,6 +18,7 @@ //#include +// TODO: Maybe we should use clang_indexSourceFile? // While indexing, we should refer to symbols by USR. When joining into the db, we can have optimized access. @@ -69,7 +70,7 @@ struct TypeDef { std::string usr; std::string short_name; std::string qualified_name; - std::optional declaration; // Forward decl. + std::optional declaration; // Forward decl. TODO: remove std::optional definition; // If set, then this is the same underlying type as the given value (ie, this @@ -85,8 +86,10 @@ struct TypeDef { std::vector funcs; std::vector vars; - // Usages. - std::vector uses; + // Every usage, useful for things like renames. + std::vector all_uses; + // Usages that a user is probably interested in. + std::vector interesting_uses; TypeDef(TypeId id, const std::string& usr) : id(id), usr(usr) { assert(usr.size() > 0); @@ -114,12 +117,20 @@ struct FuncDef { std::vector locals; // Functions which call this one. + // TODO: Functions can get called outside of just functions - for example, + // they can get called in static context (maybe redirect to main?) + // or in class initializer list (redirect to class ctor?) + // - Right now those usages will not get listed here (but they should be + // inside of all_uses). std::vector callers; // Functions that this function calls. std::vector callees; - // Usages. - std::vector uses; + // All usages. For interesting usages, see callees. + std::vector all_uses; + + // Indexer internal state. Do not expose. + bool needs_return_type_index = false; FuncDef(FuncId id, const std::string& usr) : id(id), usr(usr) { assert(usr.size() > 0); @@ -133,7 +144,6 @@ struct VarDef { std::string short_name; std::string qualified_name; std::optional declaration; - std::vector initializations; // Type of the variable. std::optional variable_type; @@ -142,7 +152,8 @@ struct VarDef { std::optional declaring_type; // Usages. - std::vector uses; + //std::vector initializations; // TODO: See if we can support this. + std::vector all_uses; VarDef(VarId id, const std::string& usr) : id(id), usr(usr) { assert(usr.size() > 0); @@ -166,6 +177,9 @@ struct ParsingDatabase { TypeId ToTypeId(const std::string& usr); FuncId ToFuncId(const std::string& usr); VarId ToVarId(const std::string& usr); + TypeId ToTypeId(const CXCursor& usr); + FuncId ToFuncId(const CXCursor& usr); + VarId ToVarId(const CXCursor& usr); TypeDef* Resolve(TypeId id); FuncDef* Resolve(FuncId id); @@ -176,6 +190,7 @@ struct ParsingDatabase { ParsingDatabase::ParsingDatabase() {} +// TODO: Optimize for const char*? TypeId ParsingDatabase::ToTypeId(const std::string& usr) { auto it = usr_to_type_id.find(usr); if (it != usr_to_type_id.end()) @@ -207,6 +222,19 @@ VarId ParsingDatabase::ToVarId(const std::string& usr) { return id; } +TypeId ParsingDatabase::ToTypeId(const CXCursor& cursor) { + return ToTypeId(clang::Cursor(cursor).get_usr()); +} + +FuncId ParsingDatabase::ToFuncId(const CXCursor& cursor) { + return ToFuncId(clang::Cursor(cursor).get_usr()); +} + +VarId ParsingDatabase::ToVarId(const CXCursor& cursor) { + return ToVarId(clang::Cursor(cursor).get_usr()); +} + + TypeDef* ParsingDatabase::Resolve(TypeId id) { return &types[id.local_id]; } @@ -312,7 +340,8 @@ std::string ParsingDatabase::ToString() { auto it = usr_to_type_id.find(""); if (it != usr_to_type_id.end()) { Resolve(it->second)->short_name = ""; - assert(Resolve(it->second)->uses.size() == 0); + assert(Resolve(it->second)->all_uses.size() == 0); + assert(Resolve(it->second)->interesting_uses.size() == 0); } #define WRITE(name) Write(writer, #name, def.name) @@ -342,7 +371,8 @@ std::string ParsingDatabase::ToString() { WRITE(types); WRITE(funcs); WRITE(vars); - WRITE(uses); + WRITE(all_uses); + WRITE(interesting_uses); writer.EndObject(); } writer.EndArray(); @@ -364,7 +394,7 @@ std::string ParsingDatabase::ToString() { WRITE(locals); WRITE(callers); WRITE(callees); - WRITE(uses); + WRITE(all_uses); writer.EndObject(); } writer.EndArray(); @@ -379,10 +409,10 @@ std::string ParsingDatabase::ToString() { WRITE(short_name); WRITE(qualified_name); WRITE(declaration); - WRITE(initializations); WRITE(variable_type); WRITE(declaring_type); - WRITE(uses); + //WRITE(initializations); + WRITE(all_uses); writer.EndObject(); } writer.EndArray(); @@ -521,11 +551,17 @@ void InsertReference(ParsingDatabase* db, std::optional func_id, clang:: clang::SourceLocation loc = referencer.get_source_location(); clang::Cursor referenced = referencer.get_referenced(); + // Try to reference the actual template, instead of a specialization. + CXCursor generic_def = clang_getSpecializedCursorTemplate(referenced.cx_cursor); + if (!clang_Cursor_isNull(generic_def)) + referenced = clang::Cursor(generic_def); + switch (referenced.get_kind()) { case CXCursor_Constructor: case CXCursor_Destructor: case CXCursor_CXXMethod: case CXCursor_FunctionDecl: + case CXCursor_FunctionTemplate: { FuncId referenced_id = db->ToFuncId(referenced.get_usr()); FuncDef* referenced_def = db->Resolve(referenced_id); @@ -536,7 +572,7 @@ void InsertReference(ParsingDatabase* db, std::optional func_id, clang:: referenced_def->callers.push_back(FuncRef(func_id.value(), loc)); } - referenced_def->uses.push_back(loc); + referenced_def->all_uses.push_back(loc); break; } @@ -547,7 +583,7 @@ void InsertReference(ParsingDatabase* db, std::optional func_id, clang:: VarId referenced_id = db->ToVarId(referenced.get_usr()); VarDef* referenced_def = db->Resolve(referenced_id); - referenced_def->uses.push_back(loc); + referenced_def->all_uses.push_back(loc); break; } default: @@ -597,7 +633,7 @@ void InsertTypeUsageAtLocation(ParsingDatabase* db, clang::Type type, const clan // Add a usage to the type of the variable. TypeId type_id = db->ToTypeId(raw_type.get_usr()); - db->Resolve(type_id)->uses.push_back(location); + db->Resolve(type_id)->interesting_uses.push_back(location); } struct VarDeclVisitorParam { @@ -691,7 +727,7 @@ void HandleVarDecl(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor var, s // TODO: Figure out how to scan initializations properly. We probably need // to scan for assignment statement, or definition+ctor. - var_def->initializations.push_back(var.get_source_location()); + //var_def->initializations.push_back(var.get_source_location()); clang::Type var_type = var.get_type().strip_qualifiers(); std::string var_type_usr = var.get_type().strip_qualifiers().get_usr(); if (var_type_usr != "") { @@ -746,16 +782,6 @@ clang::VisiterResult VisitFuncDefinition(clang::Cursor cursor, clang::Cursor par //std::cout << "VistFuncDefinition got " << cursor.ToString() << std::endl; switch (cursor.get_kind()) { - // TODO: Maybe we should default to recurse? - /* - case CXCursor_CompoundStmt: - case CXCursor_DeclStmt: - case CXCursor_CallExpr: - case CXCursor_UnexposedExpr: - case CXCursor_UnaryExpr: - return clang::VisiterResult::Recurse; - */ - case CXCursor_CallExpr: // When CallExpr points to a constructor, it does not have a child // DeclRefExpr which also points to the constructor. Normal function calls @@ -998,6 +1024,7 @@ clang::VisiterResult VisitFile(clang::Cursor cursor, clang::Cursor parent, FileP case CXCursor_CXXMethod: case CXCursor_FunctionDecl: + case CXCursor_FunctionTemplate: HandleFunc(param->db, param->ns, cursor, std::nullopt); break; @@ -1018,9 +1045,398 @@ clang::VisiterResult VisitFile(clang::Cursor cursor, clang::Cursor parent, FileP +int abortQuery(CXClientData client_data, void *reserved) { + // 0 -> continue + return 0; +} +void diagnostic(CXClientData client_data, CXDiagnosticSet, void *reserved) {} + +CXIdxClientFile enteredMainFile(CXClientData client_data, CXFile mainFile, void *reserved) { + return nullptr; +} + +CXIdxClientFile ppIncludedFile(CXClientData client_data, const CXIdxIncludedFileInfo *) { + return nullptr; +} + +CXIdxClientASTFile importedASTFile(CXClientData client_data, const CXIdxImportedASTFileInfo *) { + return nullptr; +} + +CXIdxClientContainer startedTranslationUnit(CXClientData client_data, void *reserved) { + return nullptr; +} +struct NamespaceHelper { + std::unordered_map container_usr_to_qualified_name; + + void RegisterQualifiedName(std::string usr, const CXIdxContainerInfo* container, std::string qualified_name) { + if (container) { + std::string container_usr = clang::Cursor(container->cursor).get_usr(); + auto it = container_usr_to_qualified_name.find(container_usr); + if (it != container_usr_to_qualified_name.end()) { + container_usr_to_qualified_name[usr] = it->second + qualified_name + "::"; + return; + } + } + + container_usr_to_qualified_name[usr] = qualified_name + "::"; + } + + std::string QualifiedName(const CXIdxContainerInfo* container, std::string unqualified_name) { + if (container) { + std::string container_usr = clang::Cursor(container->cursor).get_usr(); + auto it = container_usr_to_qualified_name.find(container_usr); + if (it != container_usr_to_qualified_name.end()) + return it->second + unqualified_name; + + // Anonymous namespaces are not processed by indexDeclaration. If we + // encounter one insert it into map. + if (container->cursor.kind == CXCursor_Namespace) { + assert(clang::Cursor(container->cursor).get_spelling() == ""); + container_usr_to_qualified_name[container_usr] = "::"; + return "::" + unqualified_name; + } + } + return unqualified_name; + } +}; + +struct IndexParam { + ParsingDatabase* db; + NamespaceHelper* ns; + + // Record the last type usage location we recorded. Clang will sometimes + // visit the same expression twice so we wan't to avoid double-reporting + // usage information for those locations. + clang::SourceLocation last_type_usage_location; + clang::SourceLocation last_func_usage_location; + + IndexParam(ParsingDatabase* db, NamespaceHelper* ns) : db(db), ns(ns) {} +}; + +/* +std::string GetNamespacePrefx(const CXIdxDeclInfo* decl) { + const CXIdxContainerInfo* container = decl->lexicalContainer; + while (container) { + + } +} +*/ + + +// TODO: Let's switch over to the indexer api. It can index +// the int x = get_value() bit... +// - problem: prototype ParmDecl are not parsed - we can parse this info though using FuncDecl and checking if it prototype +// - make sure type hierarchy is possible - CXIdxCXXClassDeclInfo +// - make sure namespace is possible - look at container/lexicalContainer +// - make sure method overload is possible - should be doable using existing approach +// +// - make sure template logic is possible +// * it doesn't seem like we get any template specialization logic +// * we get two decls to the same template... resolved by checking parent? maybe this will break. not sure. + +bool IsTypeDefinition(const CXIdxContainerInfo* container) { + if (!container) + return false; + + switch (container->cursor.kind) { + case CXCursor_StructDecl: + case CXCursor_ClassDecl: + return true; + default: + return false; + } +} + +void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { + IndexParam* param = static_cast(client_data); + ParsingDatabase* db = param->db; + NamespaceHelper* ns = param->ns; + + switch (decl->entityInfo->kind) { + case CXIdxEntity_CXXNamespace: + { + ns->RegisterQualifiedName(decl->entityInfo->USR, decl->semanticContainer, decl->entityInfo->name); + break; + } + + case CXIdxEntity_Field: + case CXIdxEntity_Variable: + { + VarId var_id = db->ToVarId(decl->entityInfo->USR); + VarDef* var_def = db->Resolve(var_id); + + // TODO: Eventually run with this if. Right now I want to iron out bugs this may shadow. + // TODO: Verify this gets called multiple times + //if (!decl->isRedeclaration) { + var_def->short_name = decl->entityInfo->name; + var_def->qualified_name = ns->QualifiedName(decl->semanticContainer, var_def->short_name); + //} + + var_def->declaration = decl->loc; + var_def->all_uses.push_back(decl->loc); + + clang::Type var_type = clang::Cursor(decl->cursor).get_type().strip_qualifiers(); + std::string var_type_usr = var_type.get_usr(); + if (var_type_usr != "") + var_def->variable_type = db->ToTypeId(var_type_usr); + + if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) { + TypeId declaring_type_id = db->ToTypeId(decl->semanticContainer->cursor); + TypeDef* declaring_type_def = db->Resolve(declaring_type_id); + var_def->declaring_type = declaring_type_id; + declaring_type_def->vars.push_back(var_id); + } + // std::optional declaration; + // std::vector initializations; + // std::optional variable_type; + // std::optional declaring_type; + // std::vector uses; + + break; + } + + case CXIdxEntity_Function: + case CXIdxEntity_CXXConstructor: + case CXIdxEntity_CXXInstanceMethod: + case CXIdxEntity_CXXStaticMethod: + { + FuncId func_id = db->ToFuncId(decl->entityInfo->USR); + FuncDef* func_def = db->Resolve(func_id); + + // TODO: Eventually run with this if. Right now I want to iron out bugs this may shadow. + //if (!decl->isRedeclaration) { + func_def->short_name = decl->entityInfo->name; + func_def->qualified_name = ns->QualifiedName(decl->semanticContainer, func_def->short_name); + //} + + if (decl->isDefinition) + func_def->definition = decl->loc; + + func_def->all_uses.push_back(decl->loc); + + // 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 (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) { + TypeId declaring_type_id = db->ToTypeId(decl->semanticContainer->cursor); + TypeDef* declaring_type_def = db->Resolve(declaring_type_id); + func_def->declaring_type = declaring_type_id; + declaring_type_def->funcs.push_back(func_id); + } + + // Always recompute this, as we will visit the parameter references next + // (before visiting another declaration). If we only want to mark the + // return type on the definition interesting, we could only compute this + // if we're parsing the definition declaration. + func_def->needs_return_type_index = !clang::Cursor(decl->cursor).get_type().get_return_type().is_fundamental(); + + /* + std::optional base; + std::vector derived; + std::vector locals; + std::vector callers; + std::vector callees; + std::vector uses; + */ + break; + } + + case CXIdxEntity_Struct: + case CXIdxEntity_CXXClass: + { + ns->RegisterQualifiedName(decl->entityInfo->USR, decl->semanticContainer, decl->entityInfo->name); + + TypeId type_id = db->ToTypeId(decl->entityInfo->USR); + TypeDef* type_def = db->Resolve(type_id); + + // TODO: Eventually run with this if. Right now I want to iron out bugs this may shadow. + // TODO: For type section, verify if this ever runs for non definitions? + //if (!decl->isRedeclaration) { + type_def->short_name = decl->entityInfo->name; + type_def->qualified_name = ns->QualifiedName(decl->semanticContainer, type_def->short_name); + // } + + type_def->definition = decl->loc; + + type_def->all_uses.push_back(decl->loc); + + //type_def->alias_of + //type_def->funcs + //type_def->types + //type_def->uses + //type_def->vars + + // Add type-level inheritance information. + CXIdxCXXClassDeclInfo const* class_info = clang_index_getCXXClassDeclInfo(decl); + for (unsigned int i = 0; i < class_info->numBases; ++i) { + const CXIdxBaseClassInfo* base_class = class_info->bases[i]; + + TypeId parent_type_id = db->ToTypeId(clang::Cursor(base_class->cursor).get_referenced().get_usr()); + TypeDef* parent_type_def = db->Resolve(parent_type_id); + TypeDef* type_def = db->Resolve(type_id); // type_def ptr could be invalidated by ToTypeId. + + parent_type_def->derived.push_back(type_id); + type_def->parents.push_back(parent_type_id); + } + break; + } + + default: + std::cout << "!! Unhandled indexDeclaration: " << clang::Cursor(decl->cursor).ToString() << " at " << clang::SourceLocation(decl->loc).ToString() << std::endl; + std::cout << " entityInfo->USR = " << decl->entityInfo->USR << std::endl; + if (decl->declAsContainer) + std::cout << " declAsContainer = " << clang::Cursor(decl->declAsContainer->cursor).ToString() << std::endl; + if (decl->semanticContainer) + std::cout << " semanticContainer = " << clang::Cursor(decl->semanticContainer->cursor).ToString() << std::endl; + if (decl->lexicalContainer) + std::cout << " lexicalContainer = " << clang::Cursor(decl->lexicalContainer->cursor).get_usr() << std::endl; + break; + } +} + +bool IsFunction(CXCursorKind kind) { + switch (kind) { + case CXCursor_CXXMethod: + case CXCursor_FunctionDecl: + return true; + } + + return false; +} + +void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { + IndexParam* param = static_cast(client_data); + ParsingDatabase* db = param->db; + clang::Cursor cursor(ref->cursor); + + + switch (ref->referencedEntity->kind) { + case CXIdxEntity_Variable: + case CXIdxEntity_Field: + { + VarId var_id = db->ToVarId(ref->referencedEntity->cursor); + VarDef* var_def = db->Resolve(var_id); + var_def->all_uses.push_back(ref->loc); + break; + } + + case CXIdxEntity_CXXInstanceMethod: + case CXIdxEntity_Function: + { + // TODO: Redirect container to constructor for + // int Gen() { return 5; } + // class Foo { + // int x = Gen(); + // } + + // Don't report duplicate usages. + clang::SourceLocation loc = ref->loc; + if (param->last_func_usage_location == loc) break; + param->last_func_usage_location = loc; + + // Note: be careful, calling db->ToFuncId invalidates the FuncDef* ptrs. + FuncId called_id = db->ToFuncId(ref->referencedEntity->USR); + if (IsFunction(ref->container->cursor.kind)) { + FuncId caller_id = db->ToFuncId(ref->container->cursor); + FuncDef* caller_def = db->Resolve(caller_id); + FuncDef* called_def = db->Resolve(called_id); + + caller_def->callees.push_back(FuncRef(called_id, loc)); + called_def->callers.push_back(FuncRef(caller_id, loc)); + called_def->all_uses.push_back(loc); + } + else { + FuncDef* called_def = db->Resolve(called_id); + called_def->all_uses.push_back(loc); + } + break; + } + + case CXIdxEntity_Struct: + case CXIdxEntity_CXXClass: + { + std::cout << "Reference at " << clang::SourceLocation(ref->loc).ToString() << std::endl; + TypeId referenced_id = db->ToTypeId(ref->referencedEntity->USR); + TypeDef* referenced_def = db->Resolve(referenced_id); + + // + // The following will generate two TypeRefs to Foo, both located at the + // same spot (line 3, column 3). One of the parents will be set to + // CXIdxEntity_Variable, the other will be CXIdxEntity_Function. There does + // not appear to be a good way to disambiguate these references, as using + // parent type alone breaks other indexing tasks. + // + // To work around this, we store the last type usage location. If our + // current location is the same as that location, don't report it as a + // usage. We don't need to check active type id because there can only be + // one type reference at any location in code. + // + // struct Foo {}; + // void Make() { + // Foo f; + // } + // + clang::SourceLocation loc = ref->loc; + if (param->last_type_usage_location == loc) break; + param->last_type_usage_location = loc; + + referenced_def->all_uses.push_back(loc); + + // + // Variable declarations have an embedded TypeRef. + // + if (cursor.get_kind() == CXCursor_TypeRef && + ref->parentEntity && ref->parentEntity->kind == CXIdxEntity_Variable) { + referenced_def->interesting_uses.push_back(loc); + } + + // + // If this is a type reference to a method then there will be two calls to + // this method with a TypeRef cursor kind. Only the return type is an + // interesting use (ie, Foo* is interesting, but not |Foo| in Foo::Hello). + // + // Foo* Foo::Hello() {} + // + // We handle this by adding a |needs_return_type_index| bool to FuncDef. + // It is only set to true when the type has a return value. We visit the + // return type TypeRef first, so we consume the bool and the second TypeRef + // will not get marked as interesting. + // + if (cursor.get_kind() == CXCursor_TypeRef && + ref->parentEntity && ref->parentEntity->kind == CXIdxEntity_CXXInstanceMethod) { + FuncId declaring_func_id = db->ToFuncId(ref->parentEntity->USR); + FuncDef* declaring_func_def = db->Resolve(declaring_func_id); + + if (declaring_func_def->needs_return_type_index) { + declaring_func_def->needs_return_type_index = false; + referenced_def->interesting_uses.push_back(loc); + } + } + + break; + } + + default: + std::cout << "!! Unhandled indexEntityReference: " << cursor.ToString() << " at " << clang::SourceLocation(ref->loc).ToString() << std::endl; + std::cout << " ref->referencedEntity->kind = " << ref->referencedEntity->kind << std::endl; + if (ref->parentEntity) + std::cout << " ref->parentEntity->kind = " << ref->parentEntity->kind << std::endl; + std::cout << " ref->loc = " << clang::SourceLocation(ref->loc).ToString() << std::endl; + std::cout << " ref->kind = " << ref->kind << std::endl; + if (ref->parentEntity) + std::cout << " parentEntity = " << clang::Cursor(ref->parentEntity->cursor).ToString() << std::endl; + if (ref->referencedEntity) + std::cout << " referencedEntity = " << clang::Cursor(ref->referencedEntity->cursor).ToString() << std::endl; + if (ref->container) + std::cout << " container = " << clang::Cursor(ref->container->cursor).ToString() << std::endl; + break; + } +} + ParsingDatabase Parse(std::string filename) { @@ -1029,14 +1445,51 @@ ParsingDatabase Parse(std::string filename) { clang::Index index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/); clang::TranslationUnit tu(index, filename, args); + Dump(tu.document_cursor()); + + CXIndexAction index_action = clang_IndexAction_create(index.cx_index); + + IndexerCallbacks callbacks[] = { + { &abortQuery, &diagnostic, &enteredMainFile, &ppIncludedFile, &importedASTFile, &startedTranslationUnit, &indexDeclaration, &indexEntityReference } + /* + callbacks.abortQuery = &abortQuery; + callbacks.diagnostic = &diagnostic; + callbacks.enteredMainFile = &enteredMainFile; + callbacks.ppIncludedFile = &ppIncludedFile; + callbacks.importedASTFile = &importedASTFile; + callbacks.startedTranslationUnit = &startedTranslationUnit; + callbacks.indexDeclaration = &indexDeclaration; + callbacks.indexEntityReference = &indexEntityReference; + */ + }; + + ParsingDatabase db; + NamespaceHelper ns; + IndexParam param(&db, &ns); + clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks), + CXIndexOpt_IndexFunctionLocalSymbols, tu.cx_tu); + + clang_IndexAction_dispose(index_action); + + return db; +} + + +ParsingDatabase Parse2(std::string filename) { + std::vector args; + + clang::Index index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/); + clang::TranslationUnit tu(index, filename, args); + std::cout << "Start document dump" << std::endl; Dump(tu.document_cursor()); std::cout << "Done document dump" << std::endl << std::endl; ParsingDatabase db; NamespaceStack ns; - FileParam fileParam(&db, &ns); - tu.document_cursor().VisitChildren(&VisitFile, &fileParam); + FileParam file_param(&db, &ns); + + tu.document_cursor().VisitChildren(&VisitFile, &file_param); return db; } @@ -1059,6 +1512,19 @@ void Write(const std::vector& strs) { } } + +std::string ToString(const rapidjson::Document& document) { + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + writer.SetFormatOptions( + rapidjson::PrettyFormatOptions::kFormatSingleLineArray); + writer.SetIndent(' ', 2); + + buffer.Clear(); + document.Accept(writer); + return buffer.GetString(); +} + std::vector split_string(const std::string& str, const std::string& delimiter) { // http://stackoverflow.com/a/13172514 std::vector strings; @@ -1076,31 +1542,18 @@ std::vector split_string(const std::string& str, const std::string& return strings; } + void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) { std::vector actual_output; { - rapidjson::StringBuffer buffer; - rapidjson::PrettyWriter writer(buffer); - writer.SetFormatOptions( - rapidjson::PrettyFormatOptions::kFormatSingleLineArray); - writer.SetIndent(' ', 2); - - buffer.Clear(); - actual.Accept(writer); - actual_output = split_string(buffer.GetString(), "\n"); + std::string buffer = ToString(actual); + actual_output = split_string(buffer, "\n"); } std::vector expected_output; { - rapidjson::StringBuffer buffer; - rapidjson::PrettyWriter writer(buffer); - writer.SetFormatOptions( - rapidjson::PrettyFormatOptions::kFormatSingleLineArray); - writer.SetIndent(' ', 2); - - buffer.Clear(); - expected.Accept(writer); - expected_output = split_string(buffer.GetString(), "\n"); + std::string buffer = ToString(expected); + expected_output = split_string(buffer, "\n"); } int len = std::min(actual_output.size(), expected_output.size()); @@ -1126,12 +1579,23 @@ void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) { } int main(int argc, char** argv) { + /* + ParsingDatabase db = Parse("tests/vars/function_local.cc"); + std::cout << std::endl << "== Database ==" << std::endl; + std::cout << db.ToString(); + std::cin.get(); + return 0; + */ + for (std::string path : GetFilesInFolder("tests")) { // TODO: Fix all existing tests. - //if (path != "tests/constructors/constructor.cc") continue; + //if (path == "tests/usage/type_usage_declare_extern.cc") continue; + if (path == "tests/constructors/constructor.cc") continue; //if (path != "tests/usage/type_usage_declare_local.cc") continue; - //if (path != "tests/usage/func_usage_addr_func.cc") continue; - //if (path != "tests/usage/type_usage_on_return_type.cc") continue; + //if (path != "tests/usage/func_usage_addr_method.cc") continue; + //if (path != "tests/usage/func_usage_template_func.cc") continue; + //if (path != "tests/usage/func_usage_class_inline_var_def.cc") continue; + if (path != "tests/foobar.cc") continue; // Parse expected output from the test, parse it into JSON document. std::string expected_output; diff --git a/tests/class_forward_declaration.cc b/tests/class_forward_declaration.cc index fb49889c..d4bc6434 100644 --- a/tests/class_forward_declaration.cc +++ b/tests/class_forward_declaration.cc @@ -11,8 +11,8 @@ OUTPUT: "usr": "c:@S@Foo", "short_name": "Foo", "qualified_name": "Foo", - "declaration": "tests/class_forward_declaration.cc:1:7", - "definition": "tests/class_forward_declaration.cc:3:7" + "definition": "tests/class_forward_declaration.cc:3:7", + "all_uses": ["tests/class_forward_declaration.cc:1:7", "tests/class_forward_declaration.cc:2:7", "tests/class_forward_declaration.cc:3:7", "tests/class_forward_declaration.cc:4:7"] }], "functions": [], "variables": [] diff --git a/tests/constructors/constructor.cc b/tests/constructors/constructor.cc index e8227adf..12eceb1b 100644 --- a/tests/constructors/constructor.cc +++ b/tests/constructors/constructor.cc @@ -17,7 +17,8 @@ OUTPUT: "qualified_name": "Foo", "definition": "tests/constructors/constructor.cc:1:7", "funcs": [0], - "uses": ["tests/constructors/constructor.cc:7:3"] + "all_uses": ["tests/constructors/constructor.cc:7:3"] + "interesting_uses": ["tests/constructors/constructor.cc:7:3"] }], "functions": [{ "id": 0, diff --git a/tests/constructors/destructor.cc b/tests/constructors/destructor.cc index 4f70c7a9..fcae946f 100644 --- a/tests/constructors/destructor.cc +++ b/tests/constructors/destructor.cc @@ -1,3 +1,8 @@ +// TODO: Support destructors. +// - check if variable is a pointer. if so, do *not* insert dtor +// - check if variable is normal type. if so, insert dtor +// - scan for statements that look like dtors in function def handler +// - figure out some way to support w/ unique_ptrs? /* OUTPUT: { diff --git a/tests/foobar.cc b/tests/foobar.cc new file mode 100644 index 00000000..eb2be9ec --- /dev/null +++ b/tests/foobar.cc @@ -0,0 +1,43 @@ +struct Foo { + static Foo* Used(); +}; + +void user() { + Foo* x = Foo::Used(); +} + +/* + +// TODO: Maybe only interesting usage of type is for function return type + variable declaration? +// TODO: Checking last location doesn't work for type usage all_uses... + +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@Foo", + "short_name": "Foo", + "qualified_name": "Foo", + "definition": "tests/foobar.cc:1:8", + "all_uses": ["tests/foobar.cc:1:8", "tests/foobar.cc:2:10", "tests/foobar.cc:6:3", "tests/foobar.cc:6:12", "tests/foobar.cc:6:3", "tests/foobar.cc:6:12"], + "interesting_uses": ["tests/foobar.cc:6:3", "tests/foobar.cc:6:12"] + }], + "functions": [{ + "id": 0, + "usr": "c:@F@user#", + "short_name": "user", + "qualified_name": "user", + "definition": "tests/foobar.cc:5:6", + "all_uses": ["tests/foobar.cc:5:6"] + }], + "variables": [{ + "id": 0, + "usr": "c:foobar.cc@60@F@user#@x", + "short_name": "x", + "qualified_name": "x", + "declaration": "tests/foobar.cc:6:8", + "variable_type": 0, + "all_uses": ["tests/foobar.cc:6:8"] + }] +} +*/ \ No newline at end of file diff --git a/tests/function_declaration.cc b/tests/function_declaration.cc index 9059e1c0..c0b97ce6 100644 --- a/tests/function_declaration.cc +++ b/tests/function_declaration.cc @@ -9,7 +9,7 @@ OUTPUT: "usr": "c:@F@foo#I#I#", "short_name": "foo", "qualified_name": "foo", - "declaration": "tests/function_declaration.cc:1:6" + "all_uses": ["tests/function_declaration.cc:1:6"] }], "variables": [] } diff --git a/tests/function_declaration_definition.cc b/tests/function_declaration_definition.cc index 92e5ef53..79b54516 100644 --- a/tests/function_declaration_definition.cc +++ b/tests/function_declaration_definition.cc @@ -11,8 +11,8 @@ OUTPUT: "usr": "c:@F@foo#", "short_name": "foo", "qualified_name": "foo", - "declaration": "tests/function_declaration_definition.cc:1:6", - "definition": "tests/function_declaration_definition.cc:3:6" + "definition": "tests/function_declaration_definition.cc:3:6", + "all_uses": ["tests/function_declaration_definition.cc:1:6", "tests/function_declaration_definition.cc:3:6"] }], "variables": [] } diff --git a/tests/function_definition.cc b/tests/function_definition.cc index 0ab8d667..520be3d8 100644 --- a/tests/function_definition.cc +++ b/tests/function_definition.cc @@ -9,7 +9,8 @@ OUTPUT: "usr": "c:@F@foo#", "short_name": "foo", "qualified_name": "foo", - "definition": "tests/function_definition.cc:1:6" + "definition": "tests/function_definition.cc:1:6", + "all_uses": ["tests/function_definition.cc:1:6"] }], "variables": [] } diff --git a/tests/method_declaration.cc b/tests/method_declaration.cc index c0ef6f46..b587b057 100644 --- a/tests/method_declaration.cc +++ b/tests/method_declaration.cc @@ -3,6 +3,13 @@ class Foo { }; /* +// NOTE: Lack of declaring_type in functions and funcs in Foo is okay, because +// those are processed when we find the definition for Foo::foo. +// TODO: Verify the strategy above works well with pure virtual interfaces and +// the like (ie, we need to provide a good outline view). We could just +// add the info in the declaration if the func is pure virtual - see +// clang_CXXMethod_isPureVirtual + OUTPUT: { "types": [{ @@ -11,15 +18,14 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/method_declaration.cc:1:7", - "funcs": [0] + "all_uses": ["tests/method_declaration.cc:1:7"] }], "functions": [{ "id": 0, "usr": "c:@S@Foo@F@foo#", "short_name": "foo", "qualified_name": "Foo::foo", - "declaration": "tests/method_declaration.cc:2:8", - "declaring_type": 0 + "all_uses": ["tests/method_declaration.cc:2:8"] }], "variables": [] } diff --git a/tests/method_definition.cc b/tests/method_definition.cc index 91231489..84e54775 100644 --- a/tests/method_definition.cc +++ b/tests/method_definition.cc @@ -13,16 +13,17 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/method_definition.cc:1:7", - "funcs": [0] + "funcs": [0], + "all_uses": ["tests/method_definition.cc:1:7", "tests/method_definition.cc:5:6"] }], "functions": [{ "id": 0, "usr": "c:@S@Foo@F@foo#", "short_name": "foo", "qualified_name": "Foo::foo", - "declaration": "tests/method_definition.cc:2:8", "definition": "tests/method_definition.cc:5:11", - "declaring_type": 0 + "declaring_type": 0, + "all_uses": ["tests/method_definition.cc:2:8", "tests/method_definition.cc:5:11"] }], "variables": [] } diff --git a/tests/method_inline_declaration.cc b/tests/method_inline_declaration.cc index 4e26a856..3a44d36b 100644 --- a/tests/method_inline_declaration.cc +++ b/tests/method_inline_declaration.cc @@ -11,7 +11,8 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/method_inline_declaration.cc:1:7", - "funcs": [0] + "funcs": [0], + "all_uses": ["tests/method_inline_declaration.cc:1:7"] }], "functions": [{ "id": 0, @@ -19,7 +20,8 @@ OUTPUT: "short_name": "foo", "qualified_name": "Foo::foo", "definition": "tests/method_inline_declaration.cc:2:8", - "declaring_type": 0 + "declaring_type": 0, + "all_uses": ["tests/method_inline_declaration.cc:2:8"] }], "variables": [] } diff --git a/tests/namespaces/anonymous_function.cc b/tests/namespaces/anonymous_function.cc index 0abd7b20..d763d136 100644 --- a/tests/namespaces/anonymous_function.cc +++ b/tests/namespaces/anonymous_function.cc @@ -11,7 +11,7 @@ OUTPUT: "usr": "c:anonymous_function.cc@aN@F@foo#", "short_name": "foo", "qualified_name": "::foo", - "declaration": "tests/namespaces/anonymous_function.cc:2:6" + "all_uses": ["tests/namespaces/anonymous_function.cc:2:6"] }], "variables": [] } diff --git a/tests/namespaces/function_declaration.cc b/tests/namespaces/function_declaration.cc index dfa4d699..b00bfb4e 100644 --- a/tests/namespaces/function_declaration.cc +++ b/tests/namespaces/function_declaration.cc @@ -11,7 +11,7 @@ OUTPUT: "usr": "c:@N@hello@F@foo#I#I#", "short_name": "foo", "qualified_name": "hello::foo", - "declaration": "tests/namespaces/function_declaration.cc:2:6" + "all_uses": ["tests/namespaces/function_declaration.cc:2:6"] }], "variables": [] } diff --git a/tests/namespaces/function_definition.cc b/tests/namespaces/function_definition.cc index fdb59afe..6a436f11 100644 --- a/tests/namespaces/function_definition.cc +++ b/tests/namespaces/function_definition.cc @@ -11,7 +11,8 @@ OUTPUT: "usr": "c:@N@hello@F@foo#", "short_name": "foo", "qualified_name": "hello::foo", - "definition": "tests/namespaces/function_definition.cc:2:6" + "definition": "tests/namespaces/function_definition.cc:2:6", + "all_uses": ["tests/namespaces/function_definition.cc:2:6"] }], "variables": [] } diff --git a/tests/namespaces/method_declaration.cc b/tests/namespaces/method_declaration.cc index a41a2d21..7b6ec126 100644 --- a/tests/namespaces/method_declaration.cc +++ b/tests/namespaces/method_declaration.cc @@ -13,15 +13,14 @@ OUTPUT: "short_name": "Foo", "qualified_name": "hello::Foo", "definition": "tests/namespaces/method_declaration.cc:2:7", - "funcs": [0] + "all_uses": ["tests/namespaces/method_declaration.cc:2:7"] }], "functions": [{ "id": 0, "usr": "c:@N@hello@S@Foo@F@foo#", "short_name": "foo", "qualified_name": "hello::Foo::foo", - "declaration": "tests/namespaces/method_declaration.cc:3:8", - "declaring_type": 0 + "all_uses": ["tests/namespaces/method_declaration.cc:3:8"] }], "variables": [] } diff --git a/tests/namespaces/method_definition.cc b/tests/namespaces/method_definition.cc index b63e2b9a..b79cd8a0 100644 --- a/tests/namespaces/method_definition.cc +++ b/tests/namespaces/method_definition.cc @@ -15,17 +15,18 @@ OUTPUT: "short_name": "Foo", "qualified_name": "hello::Foo", "definition": "tests/namespaces/method_definition.cc:2:7", - "funcs": [0] + "funcs": [0], + "all_uses": ["tests/namespaces/method_definition.cc:2:7", "tests/namespaces/method_definition.cc:6:6"] }], "functions": [{ "id": 0, "usr": "c:@N@hello@S@Foo@F@foo#", "short_name": "foo", "qualified_name": "hello::Foo::foo", - "declaration": "tests/namespaces/method_definition.cc:3:8", "definition": "tests/namespaces/method_definition.cc:6:11", - "declaring_type": 0 - }], + "declaring_type": 0, + "all_uses": ["tests/namespaces/method_definition.cc:3:8", "tests/namespaces/method_definition.cc:6:11"] + }], "variables": [] } */ \ No newline at end of file diff --git a/tests/namespaces/method_inline_declaration.cc b/tests/namespaces/method_inline_declaration.cc index e845fa61..2cf62c99 100644 --- a/tests/namespaces/method_inline_declaration.cc +++ b/tests/namespaces/method_inline_declaration.cc @@ -13,7 +13,8 @@ OUTPUT: "short_name": "Foo", "qualified_name": "hello::Foo", "definition": "tests/namespaces/method_inline_declaration.cc:2:7", - "funcs": [0] + "funcs": [0], + "all_uses": ["tests/namespaces/method_inline_declaration.cc:2:7"] }], "functions": [{ "id": 0, @@ -21,7 +22,8 @@ OUTPUT: "short_name": "foo", "qualified_name": "hello::Foo::foo", "definition": "tests/namespaces/method_inline_declaration.cc:3:8", - "declaring_type": 0 + "declaring_type": 0, + "all_uses": ["tests/namespaces/method_inline_declaration.cc:3:8"] }], "variables": [] } diff --git a/tests/usage/func_usage_addr_func.cc b/tests/usage/func_usage_addr_func.cc index 01ea1880..369f5ba7 100644 --- a/tests/usage/func_usage_addr_func.cc +++ b/tests/usage/func_usage_addr_func.cc @@ -18,7 +18,7 @@ OUTPUT: "qualified_name": "consume", "definition": "tests/usage/func_usage_addr_func.cc:1:6", "callers": ["2@tests/usage/func_usage_addr_func.cc:7:3"], - "uses": ["tests/usage/func_usage_addr_func.cc:7:3"] + "all_uses": ["tests/usage/func_usage_addr_func.cc:1:6", "tests/usage/func_usage_addr_func.cc:7:3"] }, { "id": 1, "usr": "c:@F@used#", @@ -26,14 +26,15 @@ OUTPUT: "qualified_name": "used", "definition": "tests/usage/func_usage_addr_func.cc:3:6", "callers": ["2@tests/usage/func_usage_addr_func.cc:6:13", "2@tests/usage/func_usage_addr_func.cc:7:12"], - "uses": ["tests/usage/func_usage_addr_func.cc:6:13", "tests/usage/func_usage_addr_func.cc:7:12"] + "all_uses": ["tests/usage/func_usage_addr_func.cc:3:6", "tests/usage/func_usage_addr_func.cc:6:13", "tests/usage/func_usage_addr_func.cc:7:12"] }, { "id": 2, "usr": "c:@F@user#", "short_name": "user", "qualified_name": "user", "definition": "tests/usage/func_usage_addr_func.cc:5:6", - "callees": ["1@tests/usage/func_usage_addr_func.cc:6:13", "0@tests/usage/func_usage_addr_func.cc:7:3", "1@tests/usage/func_usage_addr_func.cc:7:12"] + "callees": ["1@tests/usage/func_usage_addr_func.cc:6:13", "0@tests/usage/func_usage_addr_func.cc:7:3", "1@tests/usage/func_usage_addr_func.cc:7:12"], + "all_uses": ["tests/usage/func_usage_addr_func.cc:5:6"] }], "variables": [{ "id": 0, @@ -41,7 +42,7 @@ OUTPUT: "short_name": "x", "qualified_name": "x", "declaration": "tests/usage/func_usage_addr_func.cc:6:8", - "initializations": ["tests/usage/func_usage_addr_func.cc:6:8"] + "all_uses": ["tests/usage/func_usage_addr_func.cc:6:8"] }] } */ \ No newline at end of file diff --git a/tests/usage/func_usage_addr_method.cc b/tests/usage/func_usage_addr_method.cc index cc6647b0..408a60c7 100644 --- a/tests/usage/func_usage_addr_method.cc +++ b/tests/usage/func_usage_addr_method.cc @@ -16,32 +16,31 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/usage/func_usage_addr_method.cc:1:8", - "funcs": [0] + "all_uses": ["tests/usage/func_usage_addr_method.cc:1:8", "tests/usage/func_usage_addr_method.cc:6:13"] }], "functions": [{ - "id": 0, - "usr": "c:@S@Foo@F@Used#", - "short_name": "Used", - "qualified_name": "Foo::Used", - "declaration": "tests/usage/func_usage_addr_method.cc:2:8", - "declaring_type": 0, - "callers": ["1@tests/usage/func_usage_addr_method.cc:6:18"], - "uses": ["tests/usage/func_usage_addr_method.cc:6:18"] - }, { - "id": 1, - "usr": "c:@F@user#", - "short_name": "user", - "qualified_name": "user", - "definition": "tests/usage/func_usage_addr_method.cc:5:6", - "callees": ["0@tests/usage/func_usage_addr_method.cc:6:18"] - }], + "id": 0, + "usr": "c:@S@Foo@F@Used#", + "short_name": "Used", + "qualified_name": "Foo::Used", + "callers": ["1@tests/usage/func_usage_addr_method.cc:6:18"], + "all_uses": ["tests/usage/func_usage_addr_method.cc:2:8", "tests/usage/func_usage_addr_method.cc:6:18"] + }, { + "id": 1, + "usr": "c:@F@user#", + "short_name": "user", + "qualified_name": "user", + "definition": "tests/usage/func_usage_addr_method.cc:5:6", + "callees": ["0@tests/usage/func_usage_addr_method.cc:6:18"], + "all_uses": ["tests/usage/func_usage_addr_method.cc:5:6"] + }], "variables": [{ "id": 0, "usr": "c:func_usage_addr_method.cc@53@F@user#@x", "short_name": "x", "qualified_name": "x", "declaration": "tests/usage/func_usage_addr_method.cc:6:8", - "initializations": ["tests/usage/func_usage_addr_method.cc:6:8"] + "all_uses": ["tests/usage/func_usage_addr_method.cc:6:8"] }] } */ \ No newline at end of file diff --git a/tests/usage/func_usage_call_func.cc b/tests/usage/func_usage_call_func.cc index 94c88355..b4c67e6c 100644 --- a/tests/usage/func_usage_call_func.cc +++ b/tests/usage/func_usage_call_func.cc @@ -14,14 +14,15 @@ OUTPUT: "qualified_name": "called", "definition": "tests/usage/func_usage_call_func.cc:1:6", "callers": ["1@tests/usage/func_usage_call_func.cc:3:3"], - "uses": ["tests/usage/func_usage_call_func.cc:3:3"] + "all_uses": ["tests/usage/func_usage_call_func.cc:1:6", "tests/usage/func_usage_call_func.cc:3:3"] }, { "id": 1, "usr": "c:@F@caller#", "short_name": "caller", "qualified_name": "caller", "definition": "tests/usage/func_usage_call_func.cc:2:6", - "callees": ["0@tests/usage/func_usage_call_func.cc:3:3"] + "callees": ["0@tests/usage/func_usage_call_func.cc:3:3"], + "all_uses": ["tests/usage/func_usage_call_func.cc:2:6"] }], "variables": [] } diff --git a/tests/usage/func_usage_call_method.cc b/tests/usage/func_usage_call_method.cc index bef6476a..da0dac4f 100644 --- a/tests/usage/func_usage_call_method.cc +++ b/tests/usage/func_usage_call_method.cc @@ -16,25 +16,23 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/usage/func_usage_call_method.cc:1:8", - "funcs": [0], - "uses": ["tests/usage/func_usage_call_method.cc:6:3"] + "all_uses": ["tests/usage/func_usage_call_method.cc:1:8", "tests/usage/func_usage_call_method.cc:6:3"] }], "functions": [{ "id": 0, "usr": "c:@S@Foo@F@Used#", "short_name": "Used", "qualified_name": "Foo::Used", - "declaration": "tests/usage/func_usage_call_method.cc:2:8", - "declaring_type": 0, "callers": ["1@tests/usage/func_usage_call_method.cc:7:6"], - "uses": ["tests/usage/func_usage_call_method.cc:7:6"] + "all_uses": ["tests/usage/func_usage_call_method.cc:2:8", "tests/usage/func_usage_call_method.cc:7:6"] }, { "id": 1, "usr": "c:@F@user#", "short_name": "user", "qualified_name": "user", "definition": "tests/usage/func_usage_call_method.cc:5:6", - "callees": ["0@tests/usage/func_usage_call_method.cc:7:6"] + "callees": ["0@tests/usage/func_usage_call_method.cc:7:6"], + "all_uses": ["tests/usage/func_usage_call_method.cc:5:6"] }], "variables": [{ "id": 0, @@ -42,9 +40,8 @@ OUTPUT: "short_name": "f", "qualified_name": "f", "declaration": "tests/usage/func_usage_call_method.cc:6:8", - "initializations": ["tests/usage/func_usage_call_method.cc:6:8"], "variable_type": 0, - "uses": ["tests/usage/func_usage_call_method.cc:7:3"] + "all_uses": ["tests/usage/func_usage_call_method.cc:6:8", "tests/usage/func_usage_call_method.cc:7:3"] }] } */ \ No newline at end of file diff --git a/tests/usage/func_usage_class_inline_var_def.cc b/tests/usage/func_usage_class_inline_var_def.cc index baaea077..f1ed79b8 100644 --- a/tests/usage/func_usage_class_inline_var_def.cc +++ b/tests/usage/func_usage_class_inline_var_def.cc @@ -6,9 +6,6 @@ class Foo { int x = helper(); }; -// TODO(libclang): libclang doesn't expose the |helper| reference in the ast, -// so we can't add the |helper| usage. - /* OUTPUT: { @@ -18,14 +15,16 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/usage/func_usage_class_inline_var_def.cc:5:7", - "vars": [0] + "vars": [0], + "all_uses": ["tests/usage/func_usage_class_inline_var_def.cc:5:7"] }], "functions": [{ "id": 0, "usr": "c:func_usage_class_inline_var_def.cc@F@helper#", "short_name": "helper", "qualified_name": "helper", - "definition": "tests/usage/func_usage_class_inline_var_def.cc:1:12" + "definition": "tests/usage/func_usage_class_inline_var_def.cc:1:12", + "all_uses": ["tests/usage/func_usage_class_inline_var_def.cc:1:12", "tests/usage/func_usage_class_inline_var_def.cc:6:11"] }], "variables": [{ "id": 0, @@ -33,8 +32,8 @@ OUTPUT: "short_name": "x", "qualified_name": "Foo::x", "declaration": "tests/usage/func_usage_class_inline_var_def.cc:6:7", - "initializations": ["tests/usage/func_usage_class_inline_var_def.cc:6:7"], - "declaring_type": 0 + "declaring_type": 0, + "all_uses": ["tests/usage/func_usage_class_inline_var_def.cc:6:7"] }] } */ \ No newline at end of file diff --git a/tests/usage/func_usage_forward_decl_func.cc b/tests/usage/func_usage_forward_decl_func.cc index 0535542a..95380018 100644 --- a/tests/usage/func_usage_forward_decl_func.cc +++ b/tests/usage/func_usage_forward_decl_func.cc @@ -12,16 +12,16 @@ OUTPUT: "usr": "c:@F@foo#", "short_name": "foo", "qualified_name": "foo", - "declaration": "tests/usage/func_usage_forward_decl_func.cc:1:6", "callers": ["1@tests/usage/func_usage_forward_decl_func.cc:4:3"], - "uses": ["tests/usage/func_usage_forward_decl_func.cc:4:3"] + "all_uses": ["tests/usage/func_usage_forward_decl_func.cc:1:6", "tests/usage/func_usage_forward_decl_func.cc:4:3"] }, { "id": 1, "usr": "c:@F@usage#", "short_name": "usage", "qualified_name": "usage", "definition": "tests/usage/func_usage_forward_decl_func.cc:3:6", - "callees": ["0@tests/usage/func_usage_forward_decl_func.cc:4:3"] + "callees": ["0@tests/usage/func_usage_forward_decl_func.cc:4:3"], + "all_uses": ["tests/usage/func_usage_forward_decl_func.cc:3:6"] }], "variables": [] } diff --git a/tests/usage/func_usage_forward_decl_method.cc b/tests/usage/func_usage_forward_decl_method.cc index 3eccbb54..7e0357f9 100644 --- a/tests/usage/func_usage_forward_decl_method.cc +++ b/tests/usage/func_usage_forward_decl_method.cc @@ -15,25 +15,23 @@ OUTPUT: "short_name": "Foo", "qualified_name": "Foo", "definition": "tests/usage/func_usage_forward_decl_method.cc:1:8", - "funcs": [0], - "uses": ["tests/usage/func_usage_forward_decl_method.cc:6:3"] + "all_uses": ["tests/usage/func_usage_forward_decl_method.cc:1:8", "tests/usage/func_usage_forward_decl_method.cc:6:3"] }], "functions": [{ "id": 0, "usr": "c:@S@Foo@F@foo#", "short_name": "foo", "qualified_name": "Foo::foo", - "declaration": "tests/usage/func_usage_forward_decl_method.cc:2:8", - "declaring_type": 0, "callers": ["1@tests/usage/func_usage_forward_decl_method.cc:7:6"], - "uses": ["tests/usage/func_usage_forward_decl_method.cc:7:6"] + "all_uses": ["tests/usage/func_usage_forward_decl_method.cc:2:8", "tests/usage/func_usage_forward_decl_method.cc:7:6"] }, { "id": 1, "usr": "c:@F@usage#", "short_name": "usage", "qualified_name": "usage", "definition": "tests/usage/func_usage_forward_decl_method.cc:5:6", - "callees": ["0@tests/usage/func_usage_forward_decl_method.cc:7:6"] + "callees": ["0@tests/usage/func_usage_forward_decl_method.cc:7:6"], + "all_uses": ["tests/usage/func_usage_forward_decl_method.cc:5:6"] }], "variables": [{ "id": 0, @@ -41,9 +39,8 @@ OUTPUT: "short_name": "f", "qualified_name": "f", "declaration": "tests/usage/func_usage_forward_decl_method.cc:6:8", - "initializations": ["tests/usage/func_usage_forward_decl_method.cc:6:8"], "variable_type": 0, - "uses": ["tests/usage/func_usage_forward_decl_method.cc:7:3"] + "all_uses": ["tests/usage/func_usage_forward_decl_method.cc:6:8", "tests/usage/func_usage_forward_decl_method.cc:7:3"] }] } */ \ No newline at end of file diff --git a/tests/usage/func_usage_template_func.cc b/tests/usage/func_usage_template_func.cc new file mode 100644 index 00000000..572d6d3f --- /dev/null +++ b/tests/usage/func_usage_template_func.cc @@ -0,0 +1,32 @@ +template +void accept(T) {} + +void foo() { + accept(1); + accept(true); +} + +/* +OUTPUT: +{ + "types": [], + "functions": [{ + "id": 0, + "usr": "c:@FT@>1#Taccept#t0.0#v#", + "short_name": "accept", + "qualified_name": "accept", + "definition": "tests/usage/func_usage_template_func.cc:2:6", + "callers": ["1@tests/usage/func_usage_template_func.cc:5:3", "1@tests/usage/func_usage_template_func.cc:6:3"], + "all_uses": ["tests/usage/func_usage_template_func.cc:2:6", "tests/usage/func_usage_template_func.cc:5:3", "tests/usage/func_usage_template_func.cc:6:3"] + }, { + "id": 1, + "usr": "c:@F@foo#", + "short_name": "foo", + "qualified_name": "foo", + "definition": "tests/usage/func_usage_template_func.cc:4:6", + "callees": ["0@tests/usage/func_usage_template_func.cc:5:3", "0@tests/usage/func_usage_template_func.cc:6:3"], + "all_uses": ["tests/usage/func_usage_template_func.cc:4:6"] + }], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/usage/type_usage_declare_extern.cc b/tests/usage/type_usage_declare_extern.cc index b56fa5f4..8df988a6 100644 --- a/tests/usage/type_usage_declare_extern.cc +++ b/tests/usage/type_usage_declare_extern.cc @@ -10,7 +10,7 @@ OUTPUT: "short_name": "T", "qualified_name": "T", "definition": "tests/usage/type_usage_declare_extern.cc:1:8", - "uses": ["tests/usage/type_usage_declare_extern.cc:3:8"] + "all_uses": ["tests/usage/type_usage_declare_extern.cc:1:8", "tests/usage/type_usage_declare_extern.cc:3:8"] }], "functions": [], "variables": [{ @@ -18,7 +18,8 @@ OUTPUT: "usr": "c:@t", "short_name": "t", "qualified_name": "t", - "declaration": "tests/usage/type_usage_declare_extern.cc:3:10" + "declaration": "tests/usage/type_usage_declare_extern.cc:3:10", + "all_uses": ["tests/usage/type_usage_declare_extern.cc:3:10"] }] } */ \ No newline at end of file diff --git a/tests/usage/type_usage_on_return_type.cc b/tests/usage/type_usage_on_return_type.cc index 753d1936..e5427bdb 100644 --- a/tests/usage/type_usage_on_return_type.cc +++ b/tests/usage/type_usage_on_return_type.cc @@ -12,6 +12,10 @@ class Foo { Type* Foo::Get(int) {} void Foo::Empty() {} +// TODO: Add static +// TODO: Add extern? +// TODO: verify interesting usage is reported + /* OUTPUT: { diff --git a/tests/usage/type_usage_various.cc b/tests/usage/type_usage_various.cc new file mode 100644 index 00000000..5019dab0 --- /dev/null +++ b/tests/usage/type_usage_various.cc @@ -0,0 +1,52 @@ +class Foo { + Foo* make(); +}; + +Foo* Foo::make() { + Foo f; + return nullptr; +} + +extern Foo foo; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@Foo", + "short_name": "Foo", + "qualified_name": "Foo", + "definition": "tests/usage/type_usage_various.cc:1:7", + "funcs": [0], + "all_uses": ["tests/usage/type_usage_various.cc:1:7", "tests/usage/type_usage_various.cc:2:3", "tests/usage/type_usage_various.cc:5:1", "tests/usage/type_usage_various.cc:5:6", "tests/usage/type_usage_various.cc:6:3", "tests/usage/type_usage_various.cc:10:8"], + "interesting_uses": ["tests/usage/type_usage_various.cc:2:3", "tests/usage/type_usage_various.cc:5:1", "tests/usage/type_usage_various.cc:6:3", "tests/usage/type_usage_various.cc:10:8"] + }], + "functions": [{ + "id": 0, + "usr": "c:@S@Foo@F@make#", + "short_name": "make", + "qualified_name": "Foo::make", + "definition": "tests/usage/type_usage_various.cc:5:11", + "declaring_type": 0, + "all_uses": ["tests/usage/type_usage_various.cc:2:8", "tests/usage/type_usage_various.cc:5:11"] + }], + "variables": [{ + "id": 0, + "usr": "c:type_usage_various.cc@58@S@Foo@F@make#@f", + "short_name": "f", + "qualified_name": "f", + "declaration": "tests/usage/type_usage_various.cc:6:7", + "variable_type": 0, + "all_uses": ["tests/usage/type_usage_various.cc:6:7"] + }, { + "id": 1, + "usr": "c:@foo", + "short_name": "foo", + "qualified_name": "foo", + "declaration": "tests/usage/type_usage_various.cc:10:12", + "variable_type": 0, + "all_uses": ["tests/usage/type_usage_various.cc:10:12"] + }] +} +*/ \ No newline at end of file diff --git a/tests/vars/function_local.cc b/tests/vars/function_local.cc index b662f242..59b95ff2 100644 --- a/tests/vars/function_local.cc +++ b/tests/vars/function_local.cc @@ -4,22 +4,22 @@ void foo() { Foo* a; } /* +// TODO: Make sure usage for Foo is inserted into type section. + OUTPUT: { "types": [{ "id": 0, "usr": "c:@S@Foo", - "short_name": "Foo", - "qualified_name": "Foo", - "declaration": "tests/vars/function_local.cc:1:8", - "uses": ["tests/vars/function_local.cc:4:3"] + "all_uses": ["tests/vars/function_local.cc:1:8", "tests/vars/function_local.cc:4:3"] }], "functions": [{ "id": 0, "usr": "c:@F@foo#", "short_name": "foo", "qualified_name": "foo", - "definition": "tests/vars/function_local.cc:3:6" + "definition": "tests/vars/function_local.cc:3:6", + "all_uses": ["tests/vars/function_local.cc:3:6"] }], "variables": [{ "id": 0, @@ -27,8 +27,8 @@ OUTPUT: "short_name": "a", "qualified_name": "a", "declaration": "tests/vars/function_local.cc:4:8", - "initializations": ["tests/vars/function_local.cc:4:8"], - "variable_type": 0 + "variable_type": 0, + "all_uses": ["tests/vars/function_local.cc:4:8"] }] } */ \ No newline at end of file