diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b8c34ed0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/rapidjson"] + path = third_party/rapidjson + url = https://github.com/miloyip/rapidjson diff --git a/libclangmm/CMakeLists.txt b/libclangmm/CMakeListfs.txt similarity index 100% rename from libclangmm/CMakeLists.txt rename to libclangmm/CMakeListfs.txt diff --git a/libclangmm/Cursor.cc b/libclangmm/Cursor.cc index cc909be2..921e1636 100644 --- a/libclangmm/Cursor.cc +++ b/libclangmm/Cursor.cc @@ -1,27 +1,49 @@ +#include +#include + #include "Cursor.h" #include "Utility.h" -#include namespace clang { -static_assert(sizeof(Cursor) == sizeof(CXCursor), "Cursor must be the same size as CXCursor"); +Type::Type() : cx_type() {} -std::string Type::get_spelling() const { - return ToString(clang_getTypeSpelling(cx_type)); -} +Type::Type(const CXType& other) : cx_type(other) {} -Type Cursor::get_type() const { - return Type(clang_getCursorType(cx_cursor)); -} bool Type::operator==(const Type& rhs) const { return clang_equalTypes(cx_type, rhs.cx_type); } -Type Type::get_result() const { +std::string Type::get_usr() const { + return clang::Cursor(clang_getTypeDeclaration(cx_type)).get_usr(); +} + +std::string Type::get_spelling() const { + return ToString(clang_getTypeSpelling(cx_type)); +} + +Type Type::get_return_type() const { return Type(clang_getResultType(cx_type)); } +std::vector Type::get_arguments() const { + int size = clang_getNumArgTypes(cx_type); + assert(size >= 0); + if (size < 0) + return std::vector(); + + std::vector types(size); + for (int i = 0; i < size; ++i) + types.emplace_back(clang_getArgType(cx_type, i)); + return types; +} + + + +static_assert(sizeof(Cursor) == sizeof(CXCursor), + "Cursor must be the same size as CXCursor"); + Cursor::Cursor() : cx_cursor(clang_getNullCursor()) {} Cursor::Cursor(const CXCursor& other) : cx_cursor(other) {} @@ -38,24 +60,30 @@ CXCursorKind Cursor::get_kind() const { return cx_cursor.kind; } +Type Cursor::get_type() const { + return Type(clang_getCursorType(cx_cursor)); +} + SourceLocation Cursor::get_source_location() const { return SourceLocation(clang_getCursorLocation(cx_cursor)); } +/* SourceRange Cursor::get_source_range() const { return SourceRange(clang_getCursorExtent(cx_cursor)); } +*/ std::string Cursor::get_spelling() const { - return ToString(clang_getCursorSpelling(cx_cursor)); + return clang::ToString(clang_getCursorSpelling(cx_cursor)); } std::string Cursor::get_display_name() const { - return ToString(clang_getCursorDisplayName(cx_cursor)); + return clang::ToString(clang_getCursorDisplayName(cx_cursor)); } std::string Cursor::get_usr() const { - return ToString(clang_getCursorUSR(cx_cursor)); + return clang::ToString(clang_getCursorUSR(cx_cursor)); } bool Cursor::is_definition() const { @@ -79,10 +107,14 @@ Cursor Cursor::get_semantic_parent() const { } std::vector Cursor::get_arguments() const { - auto size = clang_Cursor_getNumArguments(cx_cursor); + int size = clang_Cursor_getNumArguments(cx_cursor); + assert(size >= 0); + if (size < 0) + return std::vector(); + std::vector cursors(size); - for (int c = 0; c < size; ++c) - cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, c)); + for (int i = 0; i < size; ++i) + cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, i)); return cursors; } @@ -93,7 +125,7 @@ bool Cursor::is_valid_kind() const { CXCursorKind kind = get_kind(); return kind > CXCursor_UnexposedDecl && - (kind < CXCursor_FirstInvalid || kind > CXCursor_LastInvalid); + (kind < CXCursor_FirstInvalid || kind > CXCursor_LastInvalid); } std::string Cursor::get_type_description() const { @@ -102,7 +134,7 @@ std::string Cursor::get_type_description() const { auto referenced = clang_getCursorReferenced(cx_cursor); if (!clang_Cursor_isNull(referenced)) { auto type = clang_getCursorType(referenced); - spelling = ToString(clang_getTypeSpelling(type)); + spelling = clang::ToString(clang_getTypeSpelling(type)); #if CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR<32 const std::string auto_str = "auto"; @@ -136,9 +168,13 @@ std::string Cursor::get_type_description() const { std::string Cursor::get_comments() const { Cursor referenced = get_referenced(); if (referenced) - return ToString(clang_Cursor_getRawCommentText(referenced.cx_cursor)); + return clang::ToString(clang_Cursor_getRawCommentText(referenced.cx_cursor)); return ""; } +std::string Cursor::ToString() const { + return get_spelling() + " " + clang::ToString(get_kind()); +} + } // namespace clang \ No newline at end of file diff --git a/libclangmm/Cursor.h b/libclangmm/Cursor.h index a7bcab91..e5d18fe8 100644 --- a/libclangmm/Cursor.h +++ b/libclangmm/Cursor.h @@ -14,12 +14,15 @@ namespace clang { class Type { public: - Type(const CXType &cx_type) : cx_type(cx_type) {} + Type(); + Type(const CXType& other); bool operator==(const Type& rhs) const; + std::string get_usr() const; std::string get_spelling() const; - Type get_result() const; + Type get_return_type() const; + std::vector get_arguments() const; CXType cx_type; }; @@ -41,7 +44,7 @@ public: CXCursorKind get_kind() const; Type get_type() const; SourceLocation get_source_location() const; - SourceRange get_source_range() const; + //SourceRange get_source_range() const; std::string get_spelling() const; std::string get_display_name() const; std::string get_usr() const; @@ -57,6 +60,8 @@ public: std::string get_type_description() const; std::string get_comments() const; + std::string ToString() const; + template using Visitor = VisiterResult(*)(Cursor cursor, Cursor parent, TClientData* client_data); diff --git a/libclangmm/Diagnostic.cc b/libclangmm/Diagnostic.cc index 5076e4f4..46a4f63b 100644 --- a/libclangmm/Diagnostic.cc +++ b/libclangmm/Diagnostic.cc @@ -1,3 +1,4 @@ +#if false #include "Diagnostic.h" #include "SourceLocation.h" #include "Tokens.h" @@ -39,3 +40,5 @@ const std::string clang::Diagnostic::get_severity_spelling(unsigned severity) { return ""; } } + +#endif \ No newline at end of file diff --git a/libclangmm/Diagnostic.h b/libclangmm/Diagnostic.h index 03f31273..7c6fa571 100644 --- a/libclangmm/Diagnostic.h +++ b/libclangmm/Diagnostic.h @@ -1,3 +1,5 @@ +#if false + #ifndef DIAGNOSTIC_H_ #define DIAGNOSTIC_H_ #include @@ -31,3 +33,5 @@ public: } #endif // DIAGNOSTIC_H_ + +#endif \ No newline at end of file diff --git a/libclangmm/SourceLocation.cc b/libclangmm/SourceLocation.cc index 9100ca7b..e460578a 100644 --- a/libclangmm/SourceLocation.cc +++ b/libclangmm/SourceLocation.cc @@ -1,3 +1,5 @@ +#include + #include "SourceLocation.h" #include "Utility.h" @@ -5,35 +7,27 @@ namespace clang { SourceLocation::SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned offset) { CXFile file = clang_getFile(tu, filepath.c_str()); - cx_location = clang_getLocationForOffset(tu, file, offset); + assert(false); + //cx_location = clang_getLocationForOffset(tu, file, offset); } SourceLocation::SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned line, unsigned column) { CXFile file = clang_getFile(tu, filepath.c_str()); - cx_location = clang_getLocation(tu, file, line, column); + assert(false); + //cx_location = clang_getLocation(tu, file, line, column); } -std::string SourceLocation::get_path() { - std::string path; - get_data(&path, nullptr, nullptr, nullptr); - return path; -} -Offset SourceLocation::get_offset() { - unsigned line, index; - get_data(nullptr, &line, &index, nullptr); - return{ line, index }; +SourceLocation::SourceLocation(const CXSourceLocation& cx_location) { + //clang_getExpansionLocation + + CXFile file; + clang_getSpellingLocation(cx_location, &file, &line, &column, &offset); + if (file != nullptr) + path = clang::ToString(clang_getFileName(file)); } -void SourceLocation::get_data(std::string* path, unsigned *line, unsigned *column, unsigned *offset) { - if (path == nullptr) - clang_getExpansionLocation(cx_location, nullptr, line, column, offset); - else { - CXFile file; - clang_getExpansionLocation(cx_location, &file, line, column, offset); - if (file != nullptr) { - *path = ToString(clang_getFileName(file)); - } - } +std::string SourceLocation::ToString() const { + return path + ":" + std::to_string(line) + ":" + std::to_string(column); } } \ No newline at end of file diff --git a/libclangmm/SourceLocation.h b/libclangmm/SourceLocation.h index 9d2c2138..1d8ba129 100644 --- a/libclangmm/SourceLocation.h +++ b/libclangmm/SourceLocation.h @@ -21,16 +21,14 @@ class SourceLocation { SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned offset); SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned line, unsigned column); public: - SourceLocation(const CXSourceLocation& cx_location) : cx_location(cx_location) {} + SourceLocation(const CXSourceLocation& cx_location); -public: - std::string get_path(); - clang::Offset get_offset(); + std::string path; + unsigned line; + unsigned column; + unsigned offset; - CXSourceLocation cx_location; - -private: - void get_data(std::string *path, unsigned *line, unsigned *column, unsigned *offset); + std::string ToString() const; }; } // namespace clang diff --git a/libclangmm/SourceRange.cc b/libclangmm/SourceRange.cc index c0e8407e..0f8c7bd9 100644 --- a/libclangmm/SourceRange.cc +++ b/libclangmm/SourceRange.cc @@ -1,5 +1,6 @@ #include "SourceRange.h" +/* clang::SourceRange::SourceRange(clang::SourceLocation &start, clang::SourceLocation &end) { cx_range = clang_getRange(start.cx_location, end.cx_location); } @@ -7,4 +8,5 @@ clang::SourceRange::SourceRange(clang::SourceLocation &start, clang::SourceLocat std::pair clang::SourceRange::get_offsets() { SourceLocation start(clang_getRangeStart(cx_range)), end(clang_getRangeEnd(cx_range)); return {start.get_offset(), end.get_offset()}; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/libclangmm/SourceRange.h b/libclangmm/SourceRange.h index e8edd56b..feee63f0 100644 --- a/libclangmm/SourceRange.h +++ b/libclangmm/SourceRange.h @@ -8,10 +8,12 @@ namespace clang { class SourceRange { public: + /* SourceRange(const CXSourceRange& cx_range) : cx_range(cx_range) {} SourceRange(SourceLocation &start, SourceLocation &end); std::pair get_offsets(); CXSourceRange cx_range; + */ }; } // namespace clang #endif // SOURCERANGE_H_ diff --git a/libclangmm/Token.cc b/libclangmm/Token.cc index 06c39056..2e30ba11 100644 --- a/libclangmm/Token.cc +++ b/libclangmm/Token.cc @@ -1,3 +1,4 @@ +#if false #include "Token.h" #include "Utility.h" @@ -44,3 +45,5 @@ bool clang::Token::is_identifier() const { } return false; } + +#endif \ No newline at end of file diff --git a/libclangmm/Token.h b/libclangmm/Token.h index bc24fe1d..401efa5f 100644 --- a/libclangmm/Token.h +++ b/libclangmm/Token.h @@ -1,3 +1,4 @@ +#if false #ifndef TOKEN_H_ #define TOKEN_H_ #include @@ -36,3 +37,5 @@ namespace clang { }; } // namespace clang #endif // TOKEN_H_ + +#endif \ No newline at end of file diff --git a/libclangmm/Tokens.cc b/libclangmm/Tokens.cc index 2143b3b3..5c501c88 100644 --- a/libclangmm/Tokens.cc +++ b/libclangmm/Tokens.cc @@ -1,3 +1,4 @@ +#if false #include "Tokens.h" #include "Utility.h" @@ -34,3 +35,5 @@ std::vector > clang::Tokens::get_similar } return offsets; } + +#endif \ No newline at end of file diff --git a/libclangmm/Tokens.h b/libclangmm/Tokens.h index 679b1949..679a8916 100644 --- a/libclangmm/Tokens.h +++ b/libclangmm/Tokens.h @@ -1,3 +1,4 @@ +#if false #ifndef TOKENS_H_ #define TOKENS_H_ #include @@ -24,3 +25,5 @@ namespace clang { }; } // namespace clang #endif // TOKENS_H_ + +#endif \ No newline at end of file diff --git a/libclangmm/TranslationUnit.cc b/libclangmm/TranslationUnit.cc index 729ec385..4db9db5b 100644 --- a/libclangmm/TranslationUnit.cc +++ b/libclangmm/TranslationUnit.cc @@ -89,6 +89,7 @@ CodeCompleteResults TranslationUnit::get_code_completions(const std::string &buf return results; } +/* std::vector TranslationUnit::get_diagnostics() { std::vector diagnostics; for (unsigned c = 0; c < clang_getNumDiagnostics(cx_tu); c++) { @@ -98,7 +99,9 @@ std::vector TranslationUnit::get_diagnostics() { } return diagnostics; } +*/ +/* std::unique_ptr TranslationUnit::get_tokens(unsigned start_offset, unsigned end_offset) { auto path = ToString(clang_getTranslationUnitSpelling(cx_tu)); SourceLocation start_location(cx_tu, path, start_offset); @@ -114,11 +117,13 @@ std::unique_ptr TranslationUnit::get_tokens(unsigned start_line, unsigne SourceRange range(start_location, end_location); return std::unique_ptr(new Tokens(cx_tu, range)); } +*/ Cursor TranslationUnit::document_cursor() const { return Cursor(clang_getTranslationUnitCursor(cx_tu)); } +/* Cursor TranslationUnit::get_cursor(std::string path, unsigned offset) { SourceLocation location(cx_tu, path, offset); return Cursor(clang_getCursor(cx_tu, location.cx_location)); @@ -128,5 +133,6 @@ Cursor TranslationUnit::get_cursor(std::string path, unsigned line, unsigned col SourceLocation location(cx_tu, path, line, column); return Cursor(clang_getCursor(cx_tu, location.cx_location)); } +*/ } \ No newline at end of file diff --git a/libclangmm/TranslationUnit.h b/libclangmm/TranslationUnit.h index 3def344c..8695374e 100644 --- a/libclangmm/TranslationUnit.h +++ b/libclangmm/TranslationUnit.h @@ -38,16 +38,19 @@ namespace clang { clang::CodeCompleteResults get_code_completions(const std::string &buffer, unsigned line_number, unsigned column); - std::vector get_diagnostics(); + //std::vector get_diagnostics(); + /* std::unique_ptr get_tokens(unsigned start_offset, unsigned end_offset); std::unique_ptr get_tokens(unsigned start_line, unsigned start_column, unsigned end_line, unsigned end_column); - + */ Cursor document_cursor() const; + /* clang::Cursor get_cursor(std::string path, unsigned offset); clang::Cursor get_cursor(std::string path, unsigned line, unsigned column); + */ CXTranslationUnit cx_tu; }; diff --git a/main.cpp b/main.cpp index cfbc32a2..219e523b 100644 --- a/main.cpp +++ b/main.cpp @@ -3,11 +3,18 @@ #include #include #include +#include -#include "libclangmm\clangmm.h" -#include "libclangmm\Utility.h" +#include "libclangmm/clangmm.h" +#include "libclangmm/Utility.h" #include "utils.h" + +#include +#include +#include +#include + //#include @@ -17,7 +24,7 @@ struct TypeDef; struct FuncDef; struct VarDef; - +/* template struct Id { uint64_t file_id; @@ -27,14 +34,23 @@ struct Id { Id(uint64_t file_id, uint64_t local_id) : file_id(file_id), local_id(local_id) {} }; -using TypeId = Id; -using FuncId = Id; -using VarId = Id; +*/ + +template +struct LocalId { + uint64_t local_id; + + LocalId() : local_id(0) {} // Needed for containers. Do not use directly. + explicit LocalId(uint64_t local_id) : local_id(local_id) {} +}; +using TypeId = LocalId; +using FuncId = LocalId; +using VarId = LocalId; template struct Ref { - Id id; + LocalId id; clang::SourceLocation loc; }; using TypeRef = Ref; @@ -42,14 +58,15 @@ using FuncRef = Ref; using VarRef = Ref; -struct TypeDef { - TypeDef(TypeId id); +// NOTE: declaration is empty if there is no forward declaration! +struct TypeDef { // General metadata. TypeId id; std::string usr; - std::string shortName; - std::string qualifiedName; + std::string short_name; + std::string qualified_name; + std::optional declaration; // Forward decl. std::optional definition; // Immediate parent and immediate derived types. @@ -63,25 +80,23 @@ struct TypeDef { // Usages. std::vector uses; + + TypeDef(TypeId id, const std::string& usr) : id(id), usr(usr) {} }; -TypeDef::TypeDef(TypeId id) : id(id) {} - struct FuncDef { - FuncDef(FuncId id); - // General metadata. FuncId id; std::string usr; - std::string shortName; - std::string qualifiedName; + std::string short_name; + std::string qualified_name; std::optional declaration; std::optional definition; // Type which declares this one (ie, it is a method) - std::optional declaringType; + std::optional declaring_type; // Method this method overrides. - std::optional baseFunc; + std::optional base; // Methods which directly override this one. std::vector derived; @@ -95,40 +110,38 @@ struct FuncDef { // Usages. std::vector uses; + + FuncDef(FuncId id, const std::string& usr) : id(id), usr(usr) {} }; -FuncDef::FuncDef(FuncId id) : id(id) {} - struct VarDef { - VarDef(VarId id); - // General metadata. VarId id; std::string usr; - std::string shortName; - std::string qualifiedName; + std::string short_name; + std::string qualified_name; std::optional declaration; std::vector initializations; // Type of the variable. - std::optional variableType; + std::optional variable_type; // Type which declares this one (ie, it is a method) - std::optional declaringType; + std::optional declaring_type; // Usages. std::vector uses; -}; -VarDef::VarDef(VarId id) : id(id) {} + VarDef(VarId id, const std::string& usr) : id(id), usr(usr) {} +}; struct ParsingDatabase { // NOTE: Every Id is resolved to a file_id of 0. The correct file_id needs // to get fixed up when inserting into the real db. - std::unordered_map usrToTypeId; - std::unordered_map usrToFuncId; - std::unordered_map usrToVarId; + std::unordered_map usr_to_type_id; + std::unordered_map usr_to_func_id; + std::unordered_map usr_to_var_id; std::vector types; std::vector funcs; @@ -142,37 +155,37 @@ struct ParsingDatabase { FuncDef* Resolve(FuncId id); VarDef* Resolve(VarId id); - std::vector ToString(); + std::string ToString(bool for_test); }; TypeId ParsingDatabase::ToTypeId(const std::string& usr) { - auto it = usrToTypeId.find(usr); - if (it != usrToTypeId.end()) + auto it = usr_to_type_id.find(usr); + if (it != usr_to_type_id.end()) return it->second; - TypeId id(0, types.size()); - types.push_back(TypeDef(id)); - usrToTypeId[usr] = id; + TypeId id(types.size()); + types.push_back(TypeDef(id, usr)); + usr_to_type_id[usr] = id; return id; } FuncId ParsingDatabase::ToFuncId(const std::string& usr) { - auto it = usrToFuncId.find(usr); - if (it != usrToFuncId.end()) + auto it = usr_to_func_id.find(usr); + if (it != usr_to_func_id.end()) return it->second; - FuncId id(0, funcs.size()); - funcs.push_back(FuncDef(id)); - usrToFuncId[usr] = id; + FuncId id(funcs.size()); + funcs.push_back(FuncDef(id, usr)); + usr_to_func_id[usr] = id; return id; } VarId ParsingDatabase::ToVarId(const std::string& usr) { - auto it = usrToVarId.find(usr); - if (it != usrToVarId.end()) + auto it = usr_to_var_id.find(usr); + if (it != usr_to_var_id.end()) return it->second; - VarId id(0, vars.size()); - vars.push_back(VarDef(id)); - usrToVarId[usr] = id; + VarId id(vars.size()); + vars.push_back(VarDef(id, usr)); + usr_to_var_id[usr] = id; return id; } @@ -186,25 +199,229 @@ VarDef* ParsingDatabase::Resolve(VarId id) { return &vars[id.local_id]; } -std::vector ParsingDatabase::ToString() { - std::vector result; +template +void WriteLocation(TWriter& writer, clang::SourceLocation location) { + std::string s = location.ToString(); + writer.String(s.c_str()); +} - result.push_back("Types:"); +template +void WriteLocation(TWriter& writer, std::optional location) { + if (location) + WriteLocation(writer, location.value()); + else + writer.Null(); +} + +template +void WriteId(TWriter& writer, TId id) { + writer.Uint64(id.local_id); +} + +template +void WriteId(TWriter& writer, std::optional id) { + if (id) + WriteId(writer, id.value()); + else + writer.Null(); +} + +template +void WriteRef(TWriter& writer, TRef ref) { + std::string s = std::to_string(ref.id.local_id) + "@" + ref.loc.ToString(); + writer.String(s.c_str()); +} + +template +void WriteIdArray(TWriter& writer, const std::vector& ids) { + writer.StartArray(); + for (TId id : ids) + WriteId(writer, id); + writer.EndArray(); +} + +template +void WriteRefArray(TWriter& writer, const std::vector& refs) { + writer.StartArray(); + for (TRef ref : refs) + WriteRef(writer, ref); + writer.EndArray(); +} + +template +void WriteLocationArray(TWriter& writer, const std::vector& locs) { + writer.StartArray(); + for (const clang::SourceLocation& loc : locs) + WriteLocation(writer, loc); + writer.EndArray(); +} + +std::string ParsingDatabase::ToString(bool for_test) { + rapidjson::StringBuffer output; + rapidjson::PrettyWriter writer(output); + writer.SetFormatOptions( + rapidjson::PrettyFormatOptions::kFormatSingleLineArray); + writer.SetIndent(' ', 2); + + writer.StartObject(); + + // Types + writer.Key("types"); + writer.StartArray(); for (TypeDef& def : types) { - result.push_back(" " + def.qualifiedName); - } + writer.StartObject(); - result.push_back("Funcs:"); + writer.String("id"); + writer.Uint64(def.id.local_id); + + if (!for_test) { + writer.String("usr"); + writer.String(def.usr.c_str()); + } + + writer.String("short_name"); + writer.String(def.short_name.c_str()); + + writer.String("qualified_name"); + writer.String(def.qualified_name.c_str()); + + writer.String("declaration"); + WriteLocation(writer, def.declaration); + + if (!def.definition) { + writer.EndObject(); + continue; + } + + writer.String("definition"); + WriteLocation(writer, def.definition); + + writer.String("parents"); + WriteIdArray(writer, def.parents); + + writer.String("derived"); + WriteIdArray(writer, def.derived); + + writer.String("types"); + WriteIdArray(writer, def.types); + + writer.String("funcs"); + WriteIdArray(writer, def.funcs); + + writer.String("vars"); + WriteIdArray(writer, def.vars); + + writer.String("uses"); + WriteLocationArray(writer, def.uses); + + writer.EndObject(); + } + writer.EndArray(); + + // Functions + writer.Key("functions"); + writer.StartArray(); for (FuncDef& def : funcs) { - result.push_back(" " + def.qualifiedName); - } + writer.StartObject(); - result.push_back("Vars:"); + writer.String("id"); + writer.Uint64(def.id.local_id); + + if (!for_test) { + writer.String("usr"); + writer.String(def.usr.c_str()); + } + + writer.String("short_name"); + writer.String(def.short_name.c_str()); + + writer.String("qualified_name"); + writer.String(def.qualified_name.c_str()); + + writer.String("declaration"); + WriteLocation(writer, def.declaration); + + if (def.definition) { + writer.String("definition"); + WriteLocation(writer, def.definition); + } + + if (def.definition || def.declaring_type) { + writer.String("declaring_type"); + WriteId(writer, def.declaring_type); + } + + if (def.definition) { + writer.String("base"); + WriteId(writer, def.base); + + writer.String("derived"); + WriteIdArray(writer, def.derived); + + writer.String("locals"); + WriteIdArray(writer, def.locals); + + writer.String("callers"); + WriteRefArray(writer, def.callers); + + writer.String("callees"); + WriteRefArray(writer, def.callees); + + writer.String("uses"); + WriteLocationArray(writer, def.uses); + } + + writer.EndObject(); + } + writer.EndArray(); + + // Variables + writer.Key("variables"); + writer.StartArray(); for (VarDef& def : vars) { - result.push_back(" " + def.qualifiedName); - } + writer.StartObject(); - return result; + writer.String("id"); + writer.Uint64(def.id.local_id); + + if (!for_test) { + writer.String("usr"); + writer.String(def.usr.c_str()); + } + + writer.String("short_name"); + writer.String(def.short_name.c_str()); + + writer.String("qualified_name"); + writer.String(def.qualified_name.c_str()); + + writer.String("declaration"); + WriteLocation(writer, def.declaration); + + if (def.initializations.size() == 0) { + writer.EndObject(); + continue; + } + + writer.String("initializations"); + WriteLocationArray(writer, def.initializations); + + writer.String("variable_type"); + WriteId(writer, def.variable_type); + + writer.String("declaring_type"); + WriteId(writer, def.declaring_type); + + writer.String("uses"); + WriteLocationArray(writer, def.uses); + + writer.EndObject(); + } + writer.EndArray(); + + writer.EndObject(); + + return output.GetString(); } struct FileDef { @@ -216,11 +433,11 @@ struct FileDef { }; - +/* struct Database { - std::unordered_map usrToTypeId; - std::unordered_map usrToFuncId; - std::unordered_map usrToVarId; + std::unordered_map usr_to_type_id; + std::unordered_map usr_to_func_id; + std::unordered_map usr_to_var_id; std::vector files; @@ -230,18 +447,18 @@ struct Database { }; TypeId Database::ToTypeId(const std::string& usr) { - auto it = usrToTypeId.find(usr); - assert(it != usrToTypeId.end() && "Usr is not registered"); + auto it = usr_to_type_id.find(usr); + assert(it != usr_to_type_id.end() && "Usr is not registered"); return it->second; } FuncId Database::ToFuncId(const std::string& usr) { - auto it = usrToFuncId.find(usr); - assert(it != usrToFuncId.end() && "Usr is not registered"); + auto it = usr_to_func_id.find(usr); + assert(it != usr_to_func_id.end() && "Usr is not registered"); return it->second; } VarId Database::ToVarId(const std::string& usr) { - auto it = usrToVarId.find(usr); - assert(it != usrToVarId.end() && "Usr is not registered"); + auto it = usr_to_var_id.find(usr); + assert(it != usr_to_var_id.end() && "Usr is not registered"); return it->second; } @@ -267,7 +484,7 @@ FuncDef* Resolve(Database* db, FuncId id) { VarDef* Resolve(Database* db, VarId id) { return Resolve(&db->files[id.file_id], id); } - +*/ struct NamespaceStack { std::vector stack; @@ -275,7 +492,10 @@ struct NamespaceStack { void Push(const std::string& ns); void Pop(); std::string ComputeQualifiedPrefix(); + + static NamespaceStack kEmpty; }; +NamespaceStack NamespaceStack::kEmpty; void NamespaceStack::Push(const std::string& ns) { stack.push_back(ns); @@ -295,22 +515,133 @@ std::string NamespaceStack::ComputeQualifiedPrefix() { -struct FuncDefinitionParam {}; + + + + + + +std::optional ResolveDeclaringType(CXCursorKind kind, ParsingDatabase* db, const clang::Cursor& cursor, std::optional declaring_type) { + // Resolve the declaring type for out-of-line method definitions. + if (!declaring_type && cursor.get_kind() == kind) { + clang::Cursor parent = cursor.get_semantic_parent(); + switch (parent.get_kind()) { + case CXCursor_ClassDecl: + case CXCursor_StructDecl: + declaring_type = db->ToTypeId(parent.get_usr()); + break; + } + } + + // FieldDecl, etc must have a declaring type. + assert(cursor.get_kind() != kind || declaring_type); + + return declaring_type; +} + + + + + + + + + + + + + + + +clang::VisiterResult DumpVisitor(clang::Cursor cursor, clang::Cursor parent, int* level) { + for (int i = 0; i < *level; ++i) + std::cout << " "; + std::cout << cursor.get_spelling() << " " << clang::ToString(cursor.get_kind()) << std::endl; + + *level += 1; + cursor.VisitChildren(&DumpVisitor, level); + *level -= 1; + + return clang::VisiterResult::Continue; +} + +void Dump(clang::Cursor cursor) { + int level = 0; + cursor.VisitChildren(&DumpVisitor, &level); +} + + + + + + +void HandleVarDecl(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor var, std::optional declaring_type) { + + Dump(var); + + VarId var_id = db->ToVarId(var.get_usr()); + + declaring_type = ResolveDeclaringType(CXCursor_FieldDecl, db, var, declaring_type); + + // TODO: We could use RAII to verify we don't modify db while have a *Def + // instance alive. + VarDef* var_def = db->Resolve(var_id); + var_def->short_name = var.get_spelling(); + var_def->qualified_name = ns->ComputeQualifiedPrefix() + var_def->short_name; + + if (declaring_type && !var_def->declaration) { + db->Resolve(declaring_type.value())->vars.push_back(var_id); + var_def->declaring_type = declaring_type; + } + + // We don't do any additional processing for non-definitions. + if (!var.is_definition()) { + var_def->declaration = var.get_source_location(); + return; + } + + var_def->initializations.push_back(var.get_source_location()); + var_def->variable_type = db->ToTypeId(var.get_type().get_usr()); +} + + + + + + + + + + +struct FuncDefinitionParam { + ParsingDatabase* db; + NamespaceStack* ns; + FuncDefinitionParam(ParsingDatabase* db, NamespaceStack* ns) + : db(db), ns(ns) {} +}; clang::VisiterResult VisitFuncDefinition(clang::Cursor cursor, clang::Cursor parent, FuncDefinitionParam* param) { - /* + //std::cout << "VistFunc got " << cursor.ToString() << std::endl; switch (cursor.get_kind()) { + case CXCursor_CompoundStmt: + case CXCursor_DeclStmt: + return clang::VisiterResult::Recurse; + + case CXCursor_VarDecl: + case CXCursor_ParmDecl: + HandleVarDecl(param->db, param->ns, cursor, std::nullopt); + return clang::VisiterResult::Continue; + + case CXCursor_ReturnStmt: + return clang::VisiterResult::Continue; default: std::cerr << "Unhandled VisitFuncDefinition kind " << clang::ToString(cursor.get_kind()) << std::endl; - break; + return clang::VisiterResult::Continue; } - */ - - return clang::VisiterResult::Break; } -void HandleFunc(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor func, std::optional declaringType) { +void HandleFunc(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor func, std::optional declaring_type) { // What this method must process: // - function declaration // - function definition @@ -318,21 +649,62 @@ void HandleFunc(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor func, std // - method inline definition // - method definition - // TODO: Make sure we only process once for declared/defined types. + // Resolve id before checking for is_definition so that we insert the + // function into the db even if it is only a prototype. This is needed for + // various file-level operations like outlining. + FuncId func_id = db->ToFuncId(func.get_usr()); - // TODO: method_definition_in_namespace.cc is failing because we process decl with correct declaringType, but - // processing method definition fails to resolve correct declaringType. - //if (func.is_definition()) // RM after addressed above - // return; // RM after addressed above + // TODO: Consider skipping some of this processing if we've done it already + // (ie, parsed prototype, then parse definition). - FuncId id = db->ToFuncId(func.get_usr()); - db->Resolve(id)->shortName = func.get_spelling(); + declaring_type = + ResolveDeclaringType(CXCursor_CXXMethod, db, func, declaring_type); - std::string typeName; - if (declaringType) - typeName = db->Resolve(declaringType.value())->shortName + "::"; - db->Resolve(id)->qualifiedName = ns->ComputeQualifiedPrefix() + typeName + func.get_spelling(); - std::cout << func.get_usr() << ": Set qualified name to " << db->Resolve(id)->qualifiedName << std::endl; + FuncDef* func_def = db->Resolve(func_id); + + func_def->short_name = func.get_spelling(); + std::string type_name; + if (declaring_type) + type_name = db->Resolve(declaring_type.value())->short_name + "::"; + func_def->qualified_name = + ns->ComputeQualifiedPrefix() + type_name + func_def->short_name; + + if (declaring_type && !func_def->declaration) { + db->Resolve(declaring_type.value())->funcs.push_back(func_id); + func_def->declaring_type = declaring_type; + } + + // We don't do any additional processing for non-definitions. + if (!func.is_definition()) { + func_def->declaration = func.get_source_location(); + return; + } + + func_def->definition = func.get_source_location(); + + //std::cout << "!! Types: "; + //for (clang::Cursor arg : func.get_arguments()) + // std::cout << arg.ToString() << ", "; + //std::cout << std::endl; + + //std::cout << func.get_usr() << ": Set qualified name to " << db->Resolve(id)->qualified_name; + //std::cout << " IsDefinition? " << func.is_definition() << std::endl; + + //clang::Type func_type = func.get_type(); + //clang::Type return_type = func_type.get_return_type(); + //std::vector argument_types = func_type.get_arguments(); + + //auto argument_types = func.get_arguments(); + //clang::Type cursor_type = func.get_type(); + //clang::Type return_type_1 = func.get_type().get_result(); + //clang::Type return_type_2 = clang_getCursorResultType(func.cx_cursor); + + Dump(func); + FuncDefinitionParam funcDefinitionParam(db, &NamespaceStack::kEmpty); + func.VisitChildren(&VisitFuncDefinition, &funcDefinitionParam); + + //CXType return_type = clang_getResultType(func.get_type()); + //CXType_FunctionProto //std::cout << "!! HandleFunc " << func.get_type_description() << std::endl; //std::cout << " comment: " << func.get_comments() << std::endl; @@ -362,6 +734,10 @@ clang::VisiterResult VisitClassDecl(clang::Cursor cursor, clang::Cursor parent, HandleFunc(param->db, param->ns, cursor, param->active_type); break; + case CXCursor_FieldDecl: + HandleVarDecl(param->db, param->ns, cursor, param->active_type); + break; + default: std::cerr << "Unhandled VisitClassDecl kind " << clang::ToString(cursor.get_kind()) << std::endl; break; @@ -371,11 +747,21 @@ clang::VisiterResult VisitClassDecl(clang::Cursor cursor, clang::Cursor parent, } void HandleClassDecl(clang::Cursor cursor, ParsingDatabase* db, NamespaceStack* ns) { - TypeId active_type = db->ToTypeId(cursor.get_usr()); - db->Resolve(active_type)->shortName = cursor.get_spelling(); - db->Resolve(active_type)->qualifiedName = ns->ComputeQualifiedPrefix() + cursor.get_spelling(); + TypeId id = db->ToTypeId(cursor.get_usr()); + TypeDef* def = db->Resolve(id); - ClassDeclParam classDeclParam(db, ns, active_type); + def->short_name = cursor.get_spelling(); + def->qualified_name = ns->ComputeQualifiedPrefix() + cursor.get_spelling(); + + if (!cursor.is_definition()) { + if (!def->declaration) + def->declaration = cursor.get_source_location(); + return; + } + + def->definition = cursor.get_source_location(); + + ClassDeclParam classDeclParam(db, ns, id); cursor.VisitChildren(&VisitClassDecl, &classDeclParam); } @@ -429,23 +815,6 @@ clang::VisiterResult VisitFile(clang::Cursor cursor, clang::Cursor parent, FileP -clang::VisiterResult DumpVisitor(clang::Cursor cursor, clang::Cursor parent, int* level) { - for (int i = 0; i < *level; ++i) - std::cout << " "; - std::cout << cursor.get_spelling() << " " << clang::ToString(cursor.get_kind()) << std::endl; - - *level += 1; - cursor.VisitChildren(&DumpVisitor, level); - *level -= 1; - - return clang::VisiterResult::Continue; -} - -void Dump(clang::Cursor cursor) { - int level = 0; - cursor.VisitChildren(&DumpVisitor, &level); -} - ParsingDatabase Parse(std::string filename) { std::vector args; @@ -482,28 +851,35 @@ void Write(const std::vector& strs) { } } + + int main(int argc, char** argv) { for (std::string path : GetFilesInFolder("tests")) { // TODO: Fix all existing tests. - if (path != "tests/method_definition_in_namespace.cc") continue; + //if (path != "tests/vars/class_member.cc") continue; - std::vector expected_output; + // Parse expected output from the test, parse it into JSON document. + std::string expected_output; ParseTestExpectation(path, &expected_output); + rapidjson::Document expected; + expected.Parse(expected_output.c_str()); + // Run test. std::cout << "[START] " << path << std::endl; - ParsingDatabase db = Parse(path); - std::vector actual_output = db.ToString(); + std::string actual_output = db.ToString(true /*for_test*/); + rapidjson::Document actual; + actual.Parse(actual_output.c_str()); - if (AreEqual(expected_output, actual_output)) { + if (actual == expected) { std::cout << "[PASSED] " << path << std::endl; } else { std::cout << "[FAILED] " << path << std::endl; std::cout << "Expected output for " << path << ":" << std::endl; - Write(expected_output); + std::cout << expected_output; std::cout << "Actual output for " << path << ":" << std::endl; - Write(actual_output); + std::cout << actual_output; break; } } diff --git a/tests/class_forward_declaration.cc b/tests/class_forward_declaration.cc new file mode 100644 index 00000000..5807fa67 --- /dev/null +++ b/tests/class_forward_declaration.cc @@ -0,0 +1,25 @@ +class Foo; +class Foo; +class Foo {}; +class Foo; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "Foo", + "declaration": "tests/class_forward_declaration.cc:1:7", + "definition": "tests/class_forward_declaration.cc:3:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [], + "vars": [], + "uses": [] + }], + "functions": [], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/function_declaration.cc b/tests/function_declaration.cc index 94fbe787..10599d20 100644 --- a/tests/function_declaration.cc +++ b/tests/function_declaration.cc @@ -2,8 +2,14 @@ void foo(int a, int b); /* OUTPUT: -Types: -Funcs: - foo -Vars: +{ + "types": [], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "foo", + "declaration": "tests/function_declaration.cc:1:6" + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/function_declaration_definition.cc b/tests/function_declaration_definition.cc new file mode 100644 index 00000000..eed9fbf8 --- /dev/null +++ b/tests/function_declaration_definition.cc @@ -0,0 +1,25 @@ +void foo(); + +void foo() {} + +/* +OUTPUT: +{ + "types": [], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "foo", + "declaration": "tests/function_declaration_definition.cc:1:6", + "definition": "tests/function_declaration_definition.cc:3:6", + "declaring_type": null, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/function_declaration_in_namespace.cc b/tests/function_declaration_in_namespace.cc index e0db6a0b..f9897bf3 100644 --- a/tests/function_declaration_in_namespace.cc +++ b/tests/function_declaration_in_namespace.cc @@ -4,8 +4,14 @@ void foo(int a, int b); /* OUTPUT: -Types: -Funcs: - hello::foo -Vars: +{ + "types": [], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "hello::foo", + "declaration": "tests/function_declaration_in_namespace.cc:2:6" + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/function_definition.cc b/tests/function_definition.cc index 1d3bbce9..341cedd8 100644 --- a/tests/function_definition.cc +++ b/tests/function_definition.cc @@ -1,9 +1,23 @@ -void foo(int a, int b) {} +void foo() {} /* OUTPUT: -Types: -Funcs: - foo -Vars: +{ + "types": [], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "foo", + "declaration": null, + "definition": "tests/function_definition.cc:1:6", + "declaring_type": null, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/function_definition_in_namespace.cc b/tests/function_definition_in_namespace.cc index d9fb4838..8a87694e 100644 --- a/tests/function_definition_in_namespace.cc +++ b/tests/function_definition_in_namespace.cc @@ -1,11 +1,25 @@ namespace hello { -void foo(int a, int b) {} +void foo() {} } /* OUTPUT: -Types: -Funcs: - hello::foo -Vars: +{ + "types": [], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "hello::foo", + "declaration": null, + "definition": "tests/function_definition_in_namespace.cc:2:6", + "declaring_type": null, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/method_declaration.cc b/tests/method_declaration.cc index 970b08c9..6c9b50b5 100644 --- a/tests/method_declaration.cc +++ b/tests/method_declaration.cc @@ -4,8 +4,27 @@ class Foo { /* OUTPUT: -Types: -Funcs: - foo -Vars: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "Foo", + "declaration": null, + "definition": "tests/method_declaration.cc:1:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [0], + "vars": [], + "uses": [] + }], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "Foo::foo", + "declaration": "tests/method_declaration.cc:2:8", + "declaring_type": 0 + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/method_declaration_in_namespace.cc b/tests/method_declaration_in_namespace.cc index ff3b7f37..35304c14 100644 --- a/tests/method_declaration_in_namespace.cc +++ b/tests/method_declaration_in_namespace.cc @@ -6,8 +6,27 @@ class Foo { /* OUTPUT: -Types: -Funcs: - hello::Foo::foo -Vars: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "hello::Foo", + "declaration": null, + "definition": "tests/method_declaration_in_namespace.cc:2:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [0], + "vars": [], + "uses": [] + }], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "hello::Foo::foo", + "declaration": "tests/method_declaration_in_namespace.cc:3:8", + "declaring_type": 0 + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/method_definition.cc b/tests/method_definition.cc index 3d4015d5..ae2df2dd 100644 --- a/tests/method_definition.cc +++ b/tests/method_definition.cc @@ -5,9 +5,37 @@ class Foo { void Foo::foo() {} /* +// TODO: We are not inserting methods into declaring TypeDef. + OUTPUT: -Types: -Funcs: - foo -Vars: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "Foo", + "declaration": null, + "definition": "tests/method_definition.cc:1:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [0], + "vars": [], + "uses": [] + }], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "Foo::foo", + "declaration": "tests/method_definition.cc:2:8", + "definition": "tests/method_definition.cc:5:11", + "declaring_type": 0, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/method_definition_in_namespace.cc b/tests/method_definition_in_namespace.cc index d3d77f1e..e52c463a 100644 --- a/tests/method_definition_in_namespace.cc +++ b/tests/method_definition_in_namespace.cc @@ -8,8 +8,34 @@ void Foo::foo() {} /* OUTPUT: -Types: -Funcs: - hello::Foo::foo -Vars: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "hello::Foo", + "declaration": null, + "definition": "tests/method_definition_in_namespace.cc:2:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [0], + "vars": [], + "uses": [] + }], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "hello::Foo::foo", + "declaration": "tests/method_definition_in_namespace.cc:3:8", + "definition": "tests/method_definition_in_namespace.cc:6:11", + "declaring_type": 0, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/method_inline_declaration.cc b/tests/method_inline_declaration.cc index cfd05474..35b93b3f 100644 --- a/tests/method_inline_declaration.cc +++ b/tests/method_inline_declaration.cc @@ -4,8 +4,34 @@ class Foo { /* OUTPUT: -Types: -Funcs: - foo -Vars: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "Foo", + "declaration": null, + "definition": "tests/method_inline_declaration.cc:1:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [0], + "vars": [], + "uses": [] + }], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "Foo::foo", + "declaration": null, + "definition": "tests/method_inline_declaration.cc:2:8", + "declaring_type": 0, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/method_inline_declaration_in_namespace.cc b/tests/method_inline_declaration_in_namespace.cc index 571c3b8c..2719943f 100644 --- a/tests/method_inline_declaration_in_namespace.cc +++ b/tests/method_inline_declaration_in_namespace.cc @@ -6,8 +6,34 @@ class Foo { /* OUTPUT: -Types: -Funcs: - hello::Foo::foo -Vars: +{ + "types": [{ + "id": 0, + "short_name": "Foo", + "qualified_name": "hello::Foo", + "declaration": null, + "definition": "tests/method_inline_declaration_in_namespace.cc:2:7", + "parents": [], + "derived": [], + "types": [], + "funcs": [0], + "vars": [], + "uses": [] + }], + "functions": [{ + "id": 0, + "short_name": "foo", + "qualified_name": "hello::Foo::foo", + "declaration": null, + "definition": "tests/method_inline_declaration_in_namespace.cc:3:8", + "declaring_type": 0, + "base": null, + "derived": [], + "locals": [], + "callers": [], + "callees": [], + "uses": [] + }], + "variables": [] +} */ \ No newline at end of file diff --git a/tests/vars/class_member.cc b/tests/vars/class_member.cc new file mode 100644 index 00000000..e49d2122 --- /dev/null +++ b/tests/vars/class_member.cc @@ -0,0 +1,11 @@ +class Foo { + int member; +}; +/* +OUTPUT: +{ + "types": [], + "functions": [], + "variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/class_static_member.cc b/tests/vars/class_static_member.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/class_static_member.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/class_static_member_decl_only.cc b/tests/vars/class_static_member_decl_only.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/class_static_member_decl_only.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/function_local.cc b/tests/vars/function_local.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/function_local.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/function_param.cc b/tests/vars/function_param.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/function_param.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/function_shadow_local.cc b/tests/vars/function_shadow_local.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/function_shadow_local.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/function_shadow_param.cc b/tests/vars/function_shadow_param.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/function_shadow_param.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/global_variable.cc b/tests/vars/global_variable.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/global_variable.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/tests/vars/global_variable_decl_only.cc b/tests/vars/global_variable_decl_only.cc new file mode 100644 index 00000000..56daa2fa --- /dev/null +++ b/tests/vars/global_variable_decl_only.cc @@ -0,0 +1,8 @@ +/* +OUTPUT: +{ +"types": [], +"functions": [], +"variables": [] +} +*/ \ No newline at end of file diff --git a/third_party/rapidjson b/third_party/rapidjson new file mode 160000 index 00000000..0163a53f --- /dev/null +++ b/third_party/rapidjson @@ -0,0 +1 @@ +Subproject commit 0163a53f4a1c72e6a05848a63d80eee0d8e3f387 diff --git a/utils.cc b/utils.cc index 8a5732e6..fd5ccab3 100644 --- a/utils.cc +++ b/utils.cc @@ -52,7 +52,7 @@ std::vector ReadLines(std::string filename) { return result; } -void ParseTestExpectation(std::string filename, std::vector* expected_output) { +void ParseTestExpectation(std::string filename, std::string* expected_output) { bool in_output = false; for (std::string line : ReadLines(filename)) { @@ -60,7 +60,7 @@ void ParseTestExpectation(std::string filename, std::vector* expect break; if (in_output) - expected_output->push_back(line); + *expected_output += line + "\n"; if (line == "OUTPUT:") in_output = true; diff --git a/utils.h b/utils.h index 971d8ca5..3fe81ad9 100644 --- a/utils.h +++ b/utils.h @@ -5,4 +5,4 @@ std::vector GetFilesInFolder(std::string folder); std::vector ReadLines(std::string filename); -void ParseTestExpectation(std::string filename, std::vector* expected_output); \ No newline at end of file +void ParseTestExpectation(std::string filename, std::string* expected_output); \ No newline at end of file