From 5dbde940b60cab1d6a4cd45a90aa45959f7ad84b Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Thu, 16 Feb 2017 01:35:30 -0800 Subject: [PATCH] wip --- .gitignore | 7 ++ libclangmm/CMakeLists.txt | 54 +++++++++ libclangmm/CodeCompleteResults.cc | 45 ++++++++ libclangmm/CodeCompleteResults.h | 23 ++++ libclangmm/CompilationDatabase.cc | 14 +++ libclangmm/CompilationDatabase.h | 18 +++ libclangmm/CompileCommand.cc | 21 ++++ libclangmm/CompileCommand.h | 17 +++ libclangmm/CompileCommands.cc | 21 ++++ libclangmm/CompileCommands.h | 19 ++++ libclangmm/CompletionString.cc | 28 +++++ libclangmm/CompletionString.h | 40 +++++++ libclangmm/Cursor.cc | 138 +++++++++++++++++++++++ libclangmm/Cursor.h | 51 +++++++++ libclangmm/Diagnostic.cc | 41 +++++++ libclangmm/Diagnostic.h | 32 ++++++ libclangmm/Index.cc | 9 ++ libclangmm/Index.h | 13 +++ libclangmm/SourceLocation.cc | 39 +++++++ libclangmm/SourceLocation.h | 38 +++++++ libclangmm/SourceRange.cc | 10 ++ libclangmm/SourceRange.h | 17 +++ libclangmm/Token.cc | 46 ++++++++ libclangmm/Token.h | 38 +++++++ libclangmm/Tokens.cc | 36 ++++++ libclangmm/Tokens.h | 26 +++++ libclangmm/TranslationUnit.cc | 128 +++++++++++++++++++++ libclangmm/TranslationUnit.h | 54 +++++++++ libclangmm/Utility.cc | 181 ++++++++++++++++++++++++++++++ libclangmm/Utility.h | 11 ++ libclangmm/clangmm.h | 17 +++ main.cpp | 85 ++++++++++++++ test.cc | 2 + 33 files changed, 1319 insertions(+) create mode 100644 .gitignore create mode 100644 libclangmm/CMakeLists.txt create mode 100644 libclangmm/CodeCompleteResults.cc create mode 100644 libclangmm/CodeCompleteResults.h create mode 100644 libclangmm/CompilationDatabase.cc create mode 100644 libclangmm/CompilationDatabase.h create mode 100644 libclangmm/CompileCommand.cc create mode 100644 libclangmm/CompileCommand.h create mode 100644 libclangmm/CompileCommands.cc create mode 100644 libclangmm/CompileCommands.h create mode 100644 libclangmm/CompletionString.cc create mode 100644 libclangmm/CompletionString.h create mode 100644 libclangmm/Cursor.cc create mode 100644 libclangmm/Cursor.h create mode 100644 libclangmm/Diagnostic.cc create mode 100644 libclangmm/Diagnostic.h create mode 100644 libclangmm/Index.cc create mode 100644 libclangmm/Index.h create mode 100644 libclangmm/SourceLocation.cc create mode 100644 libclangmm/SourceLocation.h create mode 100644 libclangmm/SourceRange.cc create mode 100644 libclangmm/SourceRange.h create mode 100644 libclangmm/Token.cc create mode 100644 libclangmm/Token.h create mode 100644 libclangmm/Tokens.cc create mode 100644 libclangmm/Tokens.h create mode 100644 libclangmm/TranslationUnit.cc create mode 100644 libclangmm/TranslationUnit.h create mode 100644 libclangmm/Utility.cc create mode 100644 libclangmm/Utility.h create mode 100644 libclangmm/clangmm.h create mode 100644 main.cpp create mode 100644 test.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a857ae44 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.vs +Debug +x64 +*.swp +*.sln +*.vcxproj +*.vcxproj.filters diff --git a/libclangmm/CMakeLists.txt b/libclangmm/CMakeLists.txt new file mode 100644 index 00000000..75506fc4 --- /dev/null +++ b/libclangmm/CMakeLists.txt @@ -0,0 +1,54 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3 -Wall -Wextra -Wno-unused-parameter -Wno-reorder") +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_HOME_DIRECTORY}/cmake/Modules/") + +message("Searcing for libclang") +#LIBCLANG_FOUND System has libclang. +#LIBCLANG_INCLUDE_DIRS The libclang include directories. +#LIBCLANG_LIBRARIES The libraries needed to use libclang. +#LIBCLANG_LIBRARY_DIR The path to the directory containing libclang. +#LIBCLANG_KNOWN_LLVM_VERSIONS Known LLVM release numbers. +find_package(LibClang REQUIRED) + +set(header_files + clangmm.h + CodeCompleteResults.h + CompilationDatabase.h + CompileCommand.h + CompileCommands.h + CompletionString.h + Cursor.h + Index.h + SourceLocation.h + SourceRange.h + Token.h + Tokens.h + TranslationUnit.h + Diagnostic.h + Utility.h + ) +set(cc_files + CodeCompleteResults.cc + CompilationDatabase.cc + CompileCommand.cc + CompileCommands.cc + CompletionString.cc + Cursor.cc + Index.cc + SourceLocation.cc + SourceRange.cc + Token.cc + Tokens.cc + TranslationUnit.cc + Diagnostic.cc + Utility.cc + ) + +add_library(${project_name} SHARED ${header_files} ${cc_files}) + +include_directories(${LIBCLANG_INCLUDE_DIRS}) +target_link_libraries(${project_name} ${LIBCLANG_LIBRARIES}) + +install(TARGETS ${project_name} RUNTIME DESTINATION bin LIBRARY DESTINATION lib) +install(FILES ${header_files} DESTINATION include/libclangmm) diff --git a/libclangmm/CodeCompleteResults.cc b/libclangmm/CodeCompleteResults.cc new file mode 100644 index 00000000..7d09dd0b --- /dev/null +++ b/libclangmm/CodeCompleteResults.cc @@ -0,0 +1,45 @@ +#include "CodeCompleteResults.h" +#include "CompletionString.h" +#include +#include "Utility.h" + +clang::CodeCompleteResults::CodeCompleteResults(CXTranslationUnit &cx_tu, + const std::string &buffer, + unsigned line_num, unsigned column) { + CXUnsavedFile files[1]; + auto file_path=to_string(clang_getTranslationUnitSpelling(cx_tu)); + files[0].Filename = file_path.c_str(); + files[0].Contents = buffer.c_str(); + files[0].Length = buffer.size(); + + cx_results = clang_codeCompleteAt(cx_tu, + file_path.c_str(), + line_num, + column, + files, + 1, + clang_defaultCodeCompleteOptions()|CXCodeComplete_IncludeBriefComments); + if(cx_results!=nullptr) + clang_sortCodeCompletionResults(cx_results->Results, cx_results->NumResults); +} + +clang::CodeCompleteResults::~CodeCompleteResults() { + clang_disposeCodeCompleteResults(cx_results); +} + +unsigned clang::CodeCompleteResults::size() const { + if(cx_results==nullptr) + return 0; + return cx_results->NumResults; +} + +clang::CompletionString clang::CodeCompleteResults::get(unsigned i) const { + if (i >= size()) { + throw std::invalid_argument("clang::CodeCompleteResults::get(unsigned i): i>=size()"); + } + return CompletionString(cx_results->Results[i].CompletionString); +} + +std::string clang::CodeCompleteResults::get_usr() const { + return to_string(clang_codeCompleteGetContainerUSR(cx_results)); +} diff --git a/libclangmm/CodeCompleteResults.h b/libclangmm/CodeCompleteResults.h new file mode 100644 index 00000000..64d855b6 --- /dev/null +++ b/libclangmm/CodeCompleteResults.h @@ -0,0 +1,23 @@ +#ifndef CODECOMPLETERESULTS_H_ +#define CODECOMPLETERESULTS_H_ +#include +#include +#include +#include "CompletionString.h" + +namespace clang { + class CodeCompleteResults { + friend class TranslationUnit; + + CodeCompleteResults(CXTranslationUnit &cx_tu, const std::string &buffer, + unsigned line_num, unsigned column); + public: + ~CodeCompleteResults(); + CompletionString get(unsigned index) const; + unsigned size() const; + std::string get_usr() const; + + CXCodeCompleteResults *cx_results; + }; +} // namespace clang +#endif // CODECOMPLETERESULTS_H_ diff --git a/libclangmm/CompilationDatabase.cc b/libclangmm/CompilationDatabase.cc new file mode 100644 index 00000000..46b2c83c --- /dev/null +++ b/libclangmm/CompilationDatabase.cc @@ -0,0 +1,14 @@ +#include "CompilationDatabase.h" +#include + +clang::CompilationDatabase::CompilationDatabase(const std::string &project_path) { + CXCompilationDatabase_Error error; + cx_db = clang_CompilationDatabase_fromDirectory(project_path.c_str(), &error); + if(error) { + //TODO: compile_commands.json is missing, create it? + } +} + +clang::CompilationDatabase::~CompilationDatabase() { + clang_CompilationDatabase_dispose(cx_db); +} diff --git a/libclangmm/CompilationDatabase.h b/libclangmm/CompilationDatabase.h new file mode 100644 index 00000000..37a30538 --- /dev/null +++ b/libclangmm/CompilationDatabase.h @@ -0,0 +1,18 @@ +#ifndef COMPILATIONDATABASE_H_ +#define COMPILATIONDATABASE_H_ + +#include +#include +#include + +namespace clang { + class CompilationDatabase { + public: + explicit CompilationDatabase(const std::string &project_path); + ~CompilationDatabase(); + + CXCompilationDatabase cx_db; + }; +} + +#endif // COMPILATIONDATABASE_H_ diff --git a/libclangmm/CompileCommand.cc b/libclangmm/CompileCommand.cc new file mode 100644 index 00000000..a291da50 --- /dev/null +++ b/libclangmm/CompileCommand.cc @@ -0,0 +1,21 @@ +#include "CompileCommand.h" +#include "CompileCommands.h" +#include "Utility.h" + +std::string clang::CompileCommand::get_command() { + std::string res; + unsigned N = clang_CompileCommand_getNumArgs(cx_command); + for (unsigned i = 0; i < N; i++) { + res += to_string(clang_CompileCommand_getArg(cx_command, i)); + } + return res; +} + +std::vector clang::CompileCommand::get_command_as_args() { + unsigned N = clang_CompileCommand_getNumArgs(cx_command); + std::vector res(N); + for (unsigned i = 0; i < N; i++) { + res[i] = to_string(clang_CompileCommand_getArg(cx_command, i)); + } + return res; +} diff --git a/libclangmm/CompileCommand.h b/libclangmm/CompileCommand.h new file mode 100644 index 00000000..582d2b44 --- /dev/null +++ b/libclangmm/CompileCommand.h @@ -0,0 +1,17 @@ +#ifndef COMPILECOMMAND_H_ +#define COMPILECOMMAND_H_ +#include +#include +#include + +namespace clang { + class CompileCommand { + public: + CompileCommand(const CXCompileCommand& cx_command) : cx_command(cx_command) {}; + std::string get_command(); + std::vector get_command_as_args(); + + CXCompileCommand cx_command; + }; +} +#endif // COMPILECOMMAND_H_ diff --git a/libclangmm/CompileCommands.cc b/libclangmm/CompileCommands.cc new file mode 100644 index 00000000..44fddcb0 --- /dev/null +++ b/libclangmm/CompileCommands.cc @@ -0,0 +1,21 @@ +#include "CompileCommands.h" + +clang::CompileCommands::CompileCommands(const std::string &filename, CompilationDatabase &db) { + cx_commands = + clang_CompilationDatabase_getCompileCommands(db.cx_db, filename.c_str()); + if(clang_CompileCommands_getSize(cx_commands)==0) + cx_commands = clang_CompilationDatabase_getAllCompileCommands(db.cx_db); +} + +clang::CompileCommands::~CompileCommands() { + clang_CompileCommands_dispose(cx_commands); +} + +std::vector clang::CompileCommands::get_commands() { + unsigned N = clang_CompileCommands_getSize(cx_commands); + std::vector res; + for (unsigned i = 0; i < N; i++) { + res.emplace_back(clang_CompileCommands_getCommand(cx_commands, i)); + } + return res; +} diff --git a/libclangmm/CompileCommands.h b/libclangmm/CompileCommands.h new file mode 100644 index 00000000..f822d188 --- /dev/null +++ b/libclangmm/CompileCommands.h @@ -0,0 +1,19 @@ +#ifndef COMPILECOMMANDS_H_ +#define COMPILECOMMANDS_H_ +#include "CompilationDatabase.h" +#include "CompileCommand.h" +#include +#include +#include + +namespace clang { + class CompileCommands { + public: + CompileCommands(const std::string &filename, CompilationDatabase &db); + std::vector get_commands(); + ~CompileCommands(); + + CXCompileCommands cx_commands; + }; +} +#endif // COMPILECOMMANDS_H_ diff --git a/libclangmm/CompletionString.cc b/libclangmm/CompletionString.cc new file mode 100644 index 00000000..e9b465e1 --- /dev/null +++ b/libclangmm/CompletionString.cc @@ -0,0 +1,28 @@ +#include "CompletionString.h" +#include "Utility.h" + +clang::CompletionString:: +CompletionString(const CXCompletionString &cx_completion_sting) : cx_completion_sting(cx_completion_sting) {} + +bool clang::CompletionString::available() { + return clang_getCompletionAvailability(cx_completion_sting) == CXAvailability_Available; +} + +unsigned clang::CompletionString::get_num_chunks() { + return clang_getNumCompletionChunks(cx_completion_sting); +} + +std::vector clang::CompletionString::get_chunks() { + std::vector res; + for (unsigned i = 0; i < get_num_chunks(); i++) { + res.emplace_back(to_string(clang_getCompletionChunkText(cx_completion_sting, i)), static_cast (clang_getCompletionChunkKind(cx_completion_sting, i))); + } + return res; +} + +std::string clang::CompletionString::get_brief_comments() { + return to_string(clang_getCompletionBriefComment(cx_completion_sting)); +} + +clang::CompletionChunk::CompletionChunk(std::string chunk, CompletionChunkKind kind) : + chunk(chunk), kind(kind) { } diff --git a/libclangmm/CompletionString.h b/libclangmm/CompletionString.h new file mode 100644 index 00000000..8c3b16c4 --- /dev/null +++ b/libclangmm/CompletionString.h @@ -0,0 +1,40 @@ +#ifndef COMPLETIONSTRING_H_ +#define COMPLETIONSTRING_H_ +#include +#include +#include + +namespace clang { + enum CompletionChunkKind { + CompletionChunk_Optional, CompletionChunk_TypedText, + CompletionChunk_Text, CompletionChunk_Placeholder, + CompletionChunk_Informative, CompletionChunk_CurrentParameter, + CompletionChunk_LeftParen, CompletionChunk_RightParen, + CompletionChunk_LeftBracket, CompletionChunk_RightBracket, + CompletionChunk_LeftBrace, CompletionChunk_RightBrace, + CompletionChunk_LeftAngle, CompletionChunk_RightAngle, + CompletionChunk_Comma, CompletionChunk_ResultType, + CompletionChunk_Colon, CompletionChunk_SemiColon, + CompletionChunk_Equal, CompletionChunk_HorizontalSpace, + CompletionChunk_VerticalSpace + }; + + class CompletionChunk { + public: + CompletionChunk(std::string chunk, CompletionChunkKind kind); + std::string chunk; + CompletionChunkKind kind; + }; + + class CompletionString { + public: + explicit CompletionString(const CXCompletionString &cx_completion_sting); + bool available(); + std::vector get_chunks(); + std::string get_brief_comments(); + unsigned get_num_chunks(); + + CXCompletionString cx_completion_sting; + }; +} // namespace clang +#endif // COMPLETIONSTRING_H_ diff --git a/libclangmm/Cursor.cc b/libclangmm/Cursor.cc new file mode 100644 index 00000000..3657599d --- /dev/null +++ b/libclangmm/Cursor.cc @@ -0,0 +1,138 @@ +#include "Cursor.h" +#include "Utility.h" +#include + +namespace clang { + +std::string Cursor::Type::get_spelling() const { + return to_string(clang_getTypeSpelling(cx_type)); +} + +Cursor::Type Cursor::Type::get_result() const { + return Type(clang_getResultType(cx_type)); +} + +Cursor::Cursor() = default; + +Cursor::Cursor(const CXCursor& other) : cx_cursor(cx_cursor) {} + +bool Cursor::Type::operator==(const Cursor::Type& rhs) const { + return clang_equalTypes(cx_type, rhs.cx_type); +} + +CXCursorKind Cursor::get_kind() const { + return clang_getCursorKind(cx_cursor); +} + +Cursor::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 to_string(clang_getCursorSpelling(cx_cursor)); +} + +std::string Cursor::get_display_name() const { + return to_string(clang_getCursorDisplayName(cx_cursor)); +} + +std::string Cursor::get_usr() const { + return to_string(clang_getCursorUSR(cx_cursor)); +} + +Cursor Cursor::get_referenced() const { + return Cursor(clang_getCursorReferenced(cx_cursor)); +} + +Cursor Cursor::get_canonical() const { + return Cursor(clang_getCanonicalCursor(cx_cursor)); +} + +Cursor Cursor::get_definition() const { + return Cursor(clang_getCursorDefinition(cx_cursor)); +} + +Cursor Cursor::get_semantic_parent() const { + return Cursor(clang_getCursorSemanticParent(cx_cursor)); +} + +std::vector Cursor::get_arguments() const { + auto size = clang_Cursor_getNumArguments(cx_cursor); + std::vector cursors(size); + for (int c = 0; c < size; ++c) + cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, c)); + return cursors; +} + +Cursor::operator bool() const { + return !clang_Cursor_isNull(cx_cursor); +} + +bool Cursor::operator==(const Cursor& rhs) const { + return clang_equalCursors(cx_cursor, rhs.cx_cursor); +} + +bool Cursor::is_valid_kind() const { + CXCursor referenced = clang_getCursorReferenced(cx_cursor); + if (clang_Cursor_isNull(referenced)) + return false; + + CXCursorKind kind = get_kind(); + return kind > CXCursor_UnexposedDecl && + (kind < CXCursor_FirstInvalid || kind > CXCursor_LastInvalid); +} + +std::string Cursor::get_type_description() const { + std::string spelling; + + auto referenced = clang_getCursorReferenced(cx_cursor); + if (!clang_Cursor_isNull(referenced)) { + auto type = clang_getCursorType(referenced); + spelling = to_string(clang_getTypeSpelling(type)); + +#if CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR<32 + const std::string auto_str = "auto"; + if (spelling.size() >= 4 && std::equal(auto_str.begin(), auto_str.end(), spelling.begin())) { + auto canonical_type = clang_getCanonicalType(clang_getCursorType(cx_cursor)); + auto canonical_spelling = to_string(clang_getTypeSpelling(canonical_type)); + if (spelling.size() > 5 && spelling[4] == ' ' && spelling[5] == '&' && spelling != canonical_spelling) + return canonical_spelling + " &"; + else + return canonical_spelling; + } + + const std::string const_auto_str = "const auto"; + if (spelling.size() >= 10 && std::equal(const_auto_str.begin(), const_auto_str.end(), spelling.begin())) { + auto canonical_type = clang_getCanonicalType(clang_getCursorType(cx_cursor)); + auto canonical_spelling = to_string(clang_getTypeSpelling(canonical_type)); + if (spelling.size() > 11 && spelling[10] == ' ' && spelling[11] == '&' && spelling != canonical_spelling) + return canonical_spelling + " &"; + else + return canonical_spelling; + } +#endif + } + + if (spelling.empty()) + return get_spelling(); + + return spelling; +} + +std::string Cursor::get_brief_comments() const { + Cursor referenced = get_referenced(); + if (referenced) + return to_string(clang_Cursor_getBriefCommentText(referenced.cx_cursor)); + + return ""; +} + +} // namespace clang \ No newline at end of file diff --git a/libclangmm/Cursor.h b/libclangmm/Cursor.h new file mode 100644 index 00000000..ebb3302e --- /dev/null +++ b/libclangmm/Cursor.h @@ -0,0 +1,51 @@ +#ifndef CURSOR_H_ +#define CURSOR_H_ + +#include +#include +#include + +#include "SourceLocation.h" +#include "SourceRange.h" + + +namespace clang { + class Cursor { + public: + + class Type { + public: + Type(const CXType &cx_type) : cx_type(cx_type) {} + std::string get_spelling() const; + Type get_result() const; + bool operator==(const Cursor::Type& rhs) const; + + CXType cx_type; + }; + + Cursor(); + explicit Cursor(const CXCursor& cx_cursor); + + CXCursorKind get_kind() const; + Type get_type() const; + SourceLocation get_source_location() const; + SourceRange get_source_range() const; + std::string get_spelling() const; + std::string get_display_name() const; + std::string get_usr() const; + Cursor get_referenced() const; + Cursor get_canonical() const; + Cursor get_definition() const; + Cursor get_semantic_parent() const; + std::vector get_arguments() const; + operator bool() const; + bool operator==(const Cursor& rhs) const; + + bool is_valid_kind() const; + std::string get_type_description() const; + std::string get_brief_comments() const; + + CXCursor cx_cursor = clang_getNullCursor(); + }; +} // namespace clang +#endif // CURSOR_H_ diff --git a/libclangmm/Diagnostic.cc b/libclangmm/Diagnostic.cc new file mode 100644 index 00000000..f7d4264b --- /dev/null +++ b/libclangmm/Diagnostic.cc @@ -0,0 +1,41 @@ +#include "Diagnostic.h" +#include "SourceLocation.h" +#include "Tokens.h" +#include "Utility.h" + +clang::Diagnostic::Diagnostic(CXTranslationUnit& cx_tu, CXDiagnostic& cx_diagnostic) { + severity=clang_getDiagnosticSeverity(cx_diagnostic); + severity_spelling=get_severity_spelling(severity); + spelling=to_string(clang_getDiagnosticSpelling(cx_diagnostic)); + + SourceLocation start_location(clang_getDiagnosticLocation(cx_diagnostic)); + path=start_location.get_path(); + auto start_offset=start_location.get_offset(); + Tokens tokens(cx_tu, SourceRange(start_location, start_location)); + if(tokens.size()==1) + offsets={start_offset, tokens.begin()->offsets.second}; + + unsigned num_fix_its=clang_getDiagnosticNumFixIts(cx_diagnostic); + for(unsigned c=0;c +#include +#include +#include "SourceRange.h" + +namespace clang { + class Diagnostic { + friend class TranslationUnit; + Diagnostic(CXTranslationUnit& cx_tu, CXDiagnostic& cx_diagnostic); + public: + class FixIt { + public: + FixIt(const std::string &source, const std::pair &offsets): + source(source), offsets(offsets) {} + std::string source; + std::pair offsets; + }; + + static const std::string get_severity_spelling(unsigned severity); + + unsigned severity; + std::string severity_spelling; + std::string spelling; + std::string path; + std::pair offsets; + std::vector fix_its; + }; +} + +#endif // DIAGNOSTIC_H_ diff --git a/libclangmm/Index.cc b/libclangmm/Index.cc new file mode 100644 index 00000000..23403471 --- /dev/null +++ b/libclangmm/Index.cc @@ -0,0 +1,9 @@ +#include "Index.h" + +clang::Index::Index(int excludeDeclarationsFromPCH, int displayDiagnostics) { + cx_index = clang_createIndex(excludeDeclarationsFromPCH, displayDiagnostics); +} + +clang::Index::~Index() { + clang_disposeIndex(cx_index); +} \ No newline at end of file diff --git a/libclangmm/Index.h b/libclangmm/Index.h new file mode 100644 index 00000000..cd419772 --- /dev/null +++ b/libclangmm/Index.h @@ -0,0 +1,13 @@ +#ifndef INDEX_H_ +#define INDEX_H_ +#include + +namespace clang { + class Index { + public: + Index(int excludeDeclarationsFromPCH, int displayDiagnostics); + ~Index(); + CXIndex cx_index; + }; +} // namespace clang +#endif // INDEX_H_ diff --git a/libclangmm/SourceLocation.cc b/libclangmm/SourceLocation.cc new file mode 100644 index 00000000..c7bb6f75 --- /dev/null +++ b/libclangmm/SourceLocation.cc @@ -0,0 +1,39 @@ +#include "SourceLocation.h" +#include "Utility.h" + +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); +} + +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); +} + +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 }; +} + +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 = to_string(clang_getFileName(file)); + } + } +} + +} \ No newline at end of file diff --git a/libclangmm/SourceLocation.h b/libclangmm/SourceLocation.h new file mode 100644 index 00000000..9d2c2138 --- /dev/null +++ b/libclangmm/SourceLocation.h @@ -0,0 +1,38 @@ +#ifndef SOURCELOCATION_H_ +#define SOURCELOCATION_H_ + +#include +#include + +namespace clang { + +class Offset { +public: + Offset() {} + Offset(unsigned line, unsigned index) : line(line), index(index) {} + bool operator==(const clang::Offset &o) { return (line == o.line && index == o.index); } + bool operator!=(const clang::Offset &o) { return !(*this == o); } + unsigned line; + unsigned index; //byte index in line (not char number) +}; + +class SourceLocation { + friend class TranslationUnit; + 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) {} + +public: + std::string get_path(); + clang::Offset get_offset(); + + CXSourceLocation cx_location; + +private: + void get_data(std::string *path, unsigned *line, unsigned *column, unsigned *offset); +}; + +} // namespace clang + +#endif // SOURCELOCATION_H_ diff --git a/libclangmm/SourceRange.cc b/libclangmm/SourceRange.cc new file mode 100644 index 00000000..c0e8407e --- /dev/null +++ b/libclangmm/SourceRange.cc @@ -0,0 +1,10 @@ +#include "SourceRange.h" + +clang::SourceRange::SourceRange(clang::SourceLocation &start, clang::SourceLocation &end) { + cx_range = clang_getRange(start.cx_location, end.cx_location); +} + +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 diff --git a/libclangmm/SourceRange.h b/libclangmm/SourceRange.h new file mode 100644 index 00000000..e8edd56b --- /dev/null +++ b/libclangmm/SourceRange.h @@ -0,0 +1,17 @@ +#ifndef SOURCERANGE_H_ +#define SOURCERANGE_H_ +#include +#include "SourceLocation.h" +#include +#include + +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 new file mode 100644 index 00000000..5a0e3ddf --- /dev/null +++ b/libclangmm/Token.cc @@ -0,0 +1,46 @@ +#include "Token.h" +#include "Utility.h" + +// // // // // +// Token // +// // // // // + +// returns gets an source location for this token objekt +// based on the translationunit given +clang::SourceLocation clang::Token::get_source_location() const { + return SourceLocation(clang_getTokenLocation(cx_tu, cx_token)); +} + +// returns a sourcerange that covers this token +clang::SourceRange clang::Token::get_source_range() const { + return SourceRange(clang_getTokenExtent(cx_tu, cx_token)); +} +// returns a string description of this tokens kind +std::string clang::Token::get_spelling() const { + return to_string(clang_getTokenSpelling(cx_tu, cx_token)); +} + +clang::Token::Kind clang::Token::get_kind() const { + return static_cast(clang_getTokenKind(cx_token)); +} + +bool clang::Token::is_identifier() const { + auto token_kind=get_kind(); + auto cursor=get_cursor(); + if(token_kind==clang::Token::Kind::Identifier && cursor.is_valid_kind()) + return true; + else if(token_kind==clang::Token::Kind::Keyword && cursor.is_valid_kind()) { + auto spelling=get_spelling(); + if(spelling=="operator" || (spelling=="bool" && get_cursor().get_spelling()=="operator bool")) + return true; + } + else if(token_kind==clang::Token::Kind::Punctuation && cursor.is_valid_kind()) { + auto referenced=get_cursor().get_referenced(); + if(referenced) { + auto referenced_kind=referenced.get_kind(); + if(referenced_kind== CXCursor_FunctionDecl || referenced_kind==CXCursor_CXXMethod || referenced_kind==CXCursor_Constructor) + return true; + } + } + return false; +} diff --git a/libclangmm/Token.h b/libclangmm/Token.h new file mode 100644 index 00000000..bc24fe1d --- /dev/null +++ b/libclangmm/Token.h @@ -0,0 +1,38 @@ +#ifndef TOKEN_H_ +#define TOKEN_H_ +#include +#include "SourceLocation.h" +#include "SourceRange.h" +#include "Cursor.h" +#include + +namespace clang { + class Token { + friend class Tokens; + public: + enum Kind { + Punctuation, + Keyword, + Identifier, + Literal, + Comment + }; + private: + Token(CXTranslationUnit &cx_tu, CXToken &cx_token, CXCursor &cx_cursor): + cx_tu(cx_tu), cx_token(cx_token), cx_cursor(cx_cursor), offsets(get_source_range().get_offsets()) {}; + public: + Kind get_kind() const; + std::string get_spelling() const; + SourceLocation get_source_location() const; + SourceRange get_source_range() const; + clang::Cursor get_cursor() const {return clang::Cursor(cx_cursor);} + + bool is_identifier() const; + + CXTranslationUnit &cx_tu; + CXToken& cx_token; + CXCursor& cx_cursor; + std::pair offsets; + }; +} // namespace clang +#endif // TOKEN_H_ diff --git a/libclangmm/Tokens.cc b/libclangmm/Tokens.cc new file mode 100644 index 00000000..2143b3b3 --- /dev/null +++ b/libclangmm/Tokens.cc @@ -0,0 +1,36 @@ +#include "Tokens.h" +#include "Utility.h" + +clang::Tokens::Tokens(CXTranslationUnit &cx_tu, const SourceRange &range): cx_tu(cx_tu) { + clang_tokenize(cx_tu, range.cx_range, &cx_tokens, &num_tokens); + cx_cursors.resize(num_tokens); + clang_annotateTokens(cx_tu, cx_tokens, num_tokens, cx_cursors.data()); + for (unsigned i = 0; i < num_tokens; i++) { + if(cx_cursors[i].kind==CXCursor_DeclRefExpr) { //Temporary fix to a libclang bug + auto real_cursor=clang_getCursor(cx_tu, clang_getTokenLocation(cx_tu, cx_tokens[i])); + cx_cursors[i]=real_cursor; + } + emplace_back(Token(cx_tu, cx_tokens[i], cx_cursors[i])); + } +} + +clang::Tokens::~Tokens() { + clang_disposeTokens(cx_tu, cx_tokens, size()); +} + +//This works across TranslationUnits! However, to get rename refactoring to work, +//one have to open all the files that might include a similar token +//Similar tokens defined as tokens with equal referenced cursors. +std::vector > clang::Tokens::get_similar_token_offsets(CXCursorKind kind, + const std::string &spelling, + const std::string &usr) { + std::vector > offsets; + for(auto &token: *this) { + if(token.is_identifier()) { + auto referenced=token.get_cursor().get_referenced(); + if(referenced && kind==referenced.get_kind() && spelling==token.get_spelling() && usr==referenced.get_usr()) + offsets.emplace_back(token.offsets); + } + } + return offsets; +} diff --git a/libclangmm/Tokens.h b/libclangmm/Tokens.h new file mode 100644 index 00000000..679b1949 --- /dev/null +++ b/libclangmm/Tokens.h @@ -0,0 +1,26 @@ +#ifndef TOKENS_H_ +#define TOKENS_H_ +#include +#include "SourceRange.h" +#include "Token.h" +#include +#include + +namespace clang { + class Tokens : public std::vector { + friend class TranslationUnit; + friend class Diagnostic; + Tokens(CXTranslationUnit &cx_tu, const SourceRange &range); + public: + ~Tokens(); + std::vector > get_similar_token_offsets(CXCursorKind kind, + const std::string &spelling, + const std::string &usr); + private: + CXToken *cx_tokens; + unsigned num_tokens; + std::vector cx_cursors; + CXTranslationUnit& cx_tu; + }; +} // namespace clang +#endif // TOKENS_H_ diff --git a/libclangmm/TranslationUnit.cc b/libclangmm/TranslationUnit.cc new file mode 100644 index 00000000..23e3883f --- /dev/null +++ b/libclangmm/TranslationUnit.cc @@ -0,0 +1,128 @@ +#include "TranslationUnit.h" +#include "SourceLocation.h" +#include "Tokens.h" +#include "Utility.h" +#include +#include + +#include //TODO: remove +using namespace std; //TODO: remove + +clang::TranslationUnit::TranslationUnit(Index &index, const std::string &file_path, + const std::vector &command_line_args, + const std::string &buffer, unsigned flags) { + std::vector args; + for(auto &a: command_line_args) { + args.push_back(a.c_str()); + } + + CXUnsavedFile files[1]; + files[0].Filename=file_path.c_str(); + files[0].Contents=buffer.c_str(); + files[0].Length=buffer.size(); + + cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(), + args.size(), files, 1, flags); +} + +clang::TranslationUnit::TranslationUnit(Index &index, const std::string &file_path, + const std::vector &command_line_args, + unsigned flags) { + std::vector args; + for(auto &a: command_line_args) { + args.push_back(a.c_str()); + } + + cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(), + args.size(), nullptr, 0, flags); +} + +clang::TranslationUnit::~TranslationUnit() { + clang_disposeTranslationUnit(cx_tu); +} + +void clang::TranslationUnit::parse(Index &index, const std::string &file_path, + const std::vector &command_line_args, + const std::map &buffers, unsigned flags) { + std::vector files; + for (auto &buffer : buffers) { + CXUnsavedFile file; + file.Filename = buffer.first.c_str(); + file.Contents = buffer.second.c_str(); + file.Length = buffer.second.size(); + files.push_back(file); + } + std::vector args; + for(auto &a: command_line_args) { + args.push_back(a.c_str()); + } + cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(), + args.size(), files.data(), files.size(), flags); +} + +int clang::TranslationUnit::ReparseTranslationUnit(const std::string &buffer, unsigned flags) { + CXUnsavedFile files[1]; + + auto file_path=to_string(clang_getTranslationUnitSpelling(cx_tu)); + + files[0].Filename=file_path.c_str(); + files[0].Contents=buffer.c_str(); + files[0].Length=buffer.size(); + + return clang_reparseTranslationUnit(cx_tu, 1, files, flags); +} + +unsigned clang::TranslationUnit::DefaultFlags() { + auto flags= + CXTranslationUnit_CacheCompletionResults | + CXTranslationUnit_PrecompiledPreamble | + CXTranslationUnit_Incomplete | + CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; +#if CINDEX_VERSION_MAJOR>0 || (CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR>=35) + flags|=CXTranslationUnit_KeepGoing; +#endif + return flags; +} + +clang::CodeCompleteResults clang::TranslationUnit::get_code_completions(const std::string &buffer, + unsigned line_number, unsigned column) { + CodeCompleteResults results(cx_tu, buffer, line_number, column); + return results; +} + +std::vector clang::TranslationUnit::get_diagnostics() { + std::vector diagnostics; + for(unsigned c=0;c clang::TranslationUnit::get_tokens(unsigned start_offset, unsigned end_offset) { + auto path=clang::to_string(clang_getTranslationUnitSpelling(cx_tu)); + SourceLocation start_location(cx_tu, path, start_offset); + SourceLocation end_location(cx_tu, path, end_offset); + SourceRange range(start_location, end_location); + return std::unique_ptr(new Tokens(cx_tu, range)); +} + +std::unique_ptr clang::TranslationUnit::get_tokens(unsigned start_line, unsigned start_column, + unsigned end_line, unsigned end_column) { + auto path=to_string(clang_getTranslationUnitSpelling(cx_tu)); + SourceLocation start_location(cx_tu, path, start_line, start_column); + SourceLocation end_location(cx_tu, path, end_line, end_column); + SourceRange range(start_location, end_location); + return std::unique_ptr(new Tokens(cx_tu, range)); +} + +clang::Cursor clang::TranslationUnit::get_cursor(std::string path, unsigned offset) { + SourceLocation location(cx_tu, path, offset); + return Cursor(clang_getCursor(cx_tu, location.cx_location)); +} + +clang::Cursor clang::TranslationUnit::get_cursor(std::string path, unsigned line, unsigned column) { + SourceLocation location(cx_tu, path, line, column); + return Cursor(clang_getCursor(cx_tu, location.cx_location)); +} diff --git a/libclangmm/TranslationUnit.h b/libclangmm/TranslationUnit.h new file mode 100644 index 00000000..e3d5123b --- /dev/null +++ b/libclangmm/TranslationUnit.h @@ -0,0 +1,54 @@ +#ifndef TRANSLATIONUNIT_H_ +#define TRANSLATIONUNIT_H_ +#include +#include +#include +#include +#include +#include "Index.h" +#include "Diagnostic.h" +#include "Tokens.h" +#include "CodeCompleteResults.h" +#include "Cursor.h" + +namespace clang { + class TranslationUnit { + public: + TranslationUnit(Index &index, + const std::string &file_path, + const std::vector &command_line_args, + const std::string &buffer, + unsigned flags=DefaultFlags()); + TranslationUnit(Index &index, + const std::string &file_path, + const std::vector &command_line_args, + unsigned flags=DefaultFlags()); + ~TranslationUnit(); + + int ReparseTranslationUnit(const std::string &buffer, unsigned flags=DefaultFlags()); + + static unsigned DefaultFlags(); + + void parse(Index &index, + const std::string &file_path, + const std::vector &command_line_args, + const std::map &buffers, + unsigned flags=DefaultFlags()); + + clang::CodeCompleteResults get_code_completions(const std::string &buffer, + unsigned line_number, unsigned column); + + 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); + + clang::Cursor get_cursor(std::string path, unsigned offset); + clang::Cursor get_cursor(std::string path, unsigned line, unsigned column); + + CXTranslationUnit cx_tu; + }; +} // namespace clang +#endif // TRANSLATIONUNIT_H_ + diff --git a/libclangmm/Utility.cc b/libclangmm/Utility.cc new file mode 100644 index 00000000..72f03004 --- /dev/null +++ b/libclangmm/Utility.cc @@ -0,0 +1,181 @@ +#include "Utility.h" + +std::string clang::to_string(CXString cx_string) { + std::string string; + if(cx_string.data!=nullptr) { + string=clang_getCString(cx_string); + clang_disposeString(cx_string); + } + return string; +} + +std::string clang::to_string(CXCursorKind kind) { + switch (kind) { + case CXCursor_UnexposedDecl: return "UnexposedDecl"; + case CXCursor_StructDecl: return "StructDecl"; + case CXCursor_UnionDecl: return "UnionDecl"; + case CXCursor_ClassDecl: return "ClassDecl"; + case CXCursor_EnumDecl: return "EnumDecl"; + case CXCursor_FieldDecl: return "FieldDecl"; + case CXCursor_EnumConstantDecl: return "EnumConstantDecl"; + case CXCursor_FunctionDecl: return "FunctionDecl"; + case CXCursor_VarDecl: return "VarDecl"; + case CXCursor_ParmDecl: return "ParmDecl"; + case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl"; + case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl"; + case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl"; + case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl"; + case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl"; + case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl"; + case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl"; + case CXCursor_ObjCImplementationDecl: return "ObjCImplementationDecl"; + case CXCursor_ObjCCategoryImplDecl: return "ObjCCategoryImplDecl"; + case CXCursor_TypedefDecl: return "TypedefDecl"; + case CXCursor_CXXMethod: return "CXXMethod"; + case CXCursor_Namespace: return "Namespace"; + case CXCursor_LinkageSpec: return "LinkageSpec"; + case CXCursor_Constructor: return "Constructor"; + case CXCursor_Destructor: return "Destructor"; + case CXCursor_ConversionFunction: return "ConversionFunction"; + case CXCursor_TemplateTypeParameter: return "TemplateTypeParameter"; + case CXCursor_NonTypeTemplateParameter: return "NonTypeTemplateParameter"; + case CXCursor_TemplateTemplateParameter: return "TemplateTemplateParameter"; + case CXCursor_FunctionTemplate: return "FunctionTemplate"; + case CXCursor_ClassTemplate: return "ClassTemplate"; + case CXCursor_ClassTemplatePartialSpecialization: return "ClassTemplatePartialSpecialization"; + case CXCursor_NamespaceAlias: return "NamespaceAlias"; + case CXCursor_UsingDirective: return "UsingDirective"; + case CXCursor_UsingDeclaration: return "UsingDeclaration"; + case CXCursor_TypeAliasDecl: return "TypeAliasDecl"; + case CXCursor_ObjCSynthesizeDecl: return "ObjCSynthesizeDecl"; + case CXCursor_ObjCDynamicDecl: return "ObjCDynamicDecl"; + case CXCursor_CXXAccessSpecifier: return "CXXAccessSpecifier"; + //case CXCursor_FirstDecl: return "FirstDecl"; + //case CXCursor_LastDecl: return "LastDecl"; + //case CXCursor_FirstRef: return "FirstRef"; + case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef"; + case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef"; + case CXCursor_ObjCClassRef: return "ObjCClassRef"; + case CXCursor_TypeRef: return "TypeRef"; + case CXCursor_CXXBaseSpecifier: return "CXXBaseSpecifier"; + case CXCursor_TemplateRef: return "TemplateRef"; + case CXCursor_NamespaceRef: return "NamespaceRef"; + case CXCursor_MemberRef: return "MemberRef"; + case CXCursor_LabelRef: return "LabelRef"; + case CXCursor_OverloadedDeclRef: return "OverloadedDeclRef"; + case CXCursor_VariableRef: return "VariableRef"; + //case CXCursor_LastRef: return "LastRef"; + //case CXCursor_FirstInvalid: return "FirstInvalid"; + case CXCursor_InvalidFile: return "InvalidFile"; + case CXCursor_NoDeclFound: return "NoDeclFound"; + case CXCursor_NotImplemented: return "NotImplemented"; + case CXCursor_InvalidCode: return "InvalidCode"; + //case CXCursor_LastInvalid: return "LastInvalid"; + //case CXCursor_FirstExpr: return "FirstExpr"; + case CXCursor_UnexposedExpr: return "UnexposedExpr"; + case CXCursor_DeclRefExpr: return "DeclRefExpr"; + case CXCursor_MemberRefExpr: return "MemberRefExpr"; + case CXCursor_CallExpr: return "CallExpr"; + case CXCursor_ObjCMessageExpr: return "ObjCMessageExpr"; + case CXCursor_BlockExpr: return "BlockExpr"; + case CXCursor_IntegerLiteral: return "IntegerLiteral"; + case CXCursor_FloatingLiteral: return "FloatingLiteral"; + case CXCursor_ImaginaryLiteral: return "ImaginaryLiteral"; + case CXCursor_StringLiteral: return "StringLiteral"; + case CXCursor_CharacterLiteral: return "CharacterLiteral"; + case CXCursor_ParenExpr: return "ParenExpr"; + case CXCursor_UnaryOperator: return "UnaryOperator"; + case CXCursor_ArraySubscriptExpr: return "ArraySubscriptExpr"; + case CXCursor_BinaryOperator: return "BinaryOperator"; + case CXCursor_CompoundAssignOperator: return "CompoundAssignOperator"; + case CXCursor_ConditionalOperator: return "ConditionalOperator"; + case CXCursor_CStyleCastExpr: return "CStyleCastExpr"; + case CXCursor_CompoundLiteralExpr: return "CompoundLiteralExpr"; + case CXCursor_InitListExpr: return "InitListExpr"; + case CXCursor_AddrLabelExpr: return "AddrLabelExpr"; + case CXCursor_StmtExpr: return "StmtExpr"; + case CXCursor_GenericSelectionExpr: return "GenericSelectionExpr"; + case CXCursor_GNUNullExpr: return "GNUNullExpr"; + case CXCursor_CXXStaticCastExpr: return "CXXStaticCastExpr"; + case CXCursor_CXXDynamicCastExpr: return "CXXDynamicCastExpr"; + case CXCursor_CXXReinterpretCastExpr: return "CXXReinterpretCastExpr"; + case CXCursor_CXXConstCastExpr: return "CXXConstCastExpr"; + case CXCursor_CXXFunctionalCastExpr: return "CXXFunctionalCastExpr"; + case CXCursor_CXXTypeidExpr: return "CXXTypeidExpr"; + case CXCursor_CXXBoolLiteralExpr: return "CXXBoolLiteralExpr"; + case CXCursor_CXXNullPtrLiteralExpr: return "CXXNullPtrLiteralExpr"; + case CXCursor_CXXThisExpr: return "CXXThisExpr"; + case CXCursor_CXXThrowExpr: return "CXXThrowExpr"; + case CXCursor_CXXNewExpr: return "CXXNewExpr"; + case CXCursor_CXXDeleteExpr: return "CXXDeleteExpr"; + case CXCursor_UnaryExpr: return "UnaryExpr"; + case CXCursor_ObjCStringLiteral: return "ObjCStringLiteral"; + case CXCursor_ObjCEncodeExpr: return "ObjCEncodeExpr"; + case CXCursor_ObjCSelectorExpr: return "ObjCSelectorExpr"; + case CXCursor_ObjCProtocolExpr: return "ObjCProtocolExpr"; + case CXCursor_ObjCBridgedCastExpr: return "ObjCBridgedCastExpr"; + case CXCursor_PackExpansionExpr: return "PackExpansionExpr"; + case CXCursor_SizeOfPackExpr: return "SizeOfPackExpr"; + case CXCursor_LambdaExpr: return "LambdaExpr"; + case CXCursor_ObjCBoolLiteralExpr: return "ObjCBoolLiteralExpr"; + case CXCursor_ObjCSelfExpr: return "ObjCSelfExpr"; + //case CXCursor_LastExpr: return "LastExpr"; + //case CXCursor_FirstStmt: return "FirstStmt"; + case CXCursor_UnexposedStmt: return "UnexposedStmt"; + case CXCursor_LabelStmt: return "LabelStmt"; + case CXCursor_CompoundStmt: return "CompoundStmt"; + case CXCursor_CaseStmt: return "CaseStmt"; + case CXCursor_DefaultStmt: return "DefaultStmt"; + case CXCursor_IfStmt: return "IfStmt"; + case CXCursor_SwitchStmt: return "SwitchStmt"; + case CXCursor_WhileStmt: return "WhileStmt"; + case CXCursor_DoStmt: return "DoStmt"; + case CXCursor_ForStmt: return "ForStmt"; + case CXCursor_GotoStmt: return "GotoStmt"; + case CXCursor_IndirectGotoStmt: return "IndirectGotoStmt"; + case CXCursor_ContinueStmt: return "ContinueStmt"; + case CXCursor_BreakStmt: return "BreakStmt"; + case CXCursor_ReturnStmt: return "ReturnStmt"; + case CXCursor_GCCAsmStmt: return "GCCAsmStmt"; + //case CXCursor_AsmStmt: return "AsmStmt"; + case CXCursor_ObjCAtTryStmt: return "ObjCAtTryStmt"; + case CXCursor_ObjCAtCatchStmt: return "ObjCAtCatchStmt"; + case CXCursor_ObjCAtFinallyStmt: return "ObjCAtFinallyStmt"; + case CXCursor_ObjCAtThrowStmt: return "ObjCAtThrowStmt"; + case CXCursor_ObjCAtSynchronizedStmt: return "ObjCAtSynchronizedStmt"; + case CXCursor_ObjCAutoreleasePoolStmt: return "ObjCAutoreleasePoolStmt"; + case CXCursor_ObjCForCollectionStmt: return "ObjCForCollectionStmt"; + case CXCursor_CXXCatchStmt: return "CXXCatchStmt"; + case CXCursor_CXXTryStmt: return "CXXTryStmt"; + case CXCursor_CXXForRangeStmt: return "CXXForRangeStmt"; + case CXCursor_SEHTryStmt: return "SEHTryStmt"; + case CXCursor_SEHExceptStmt: return "SEHExceptStmt"; + case CXCursor_SEHFinallyStmt: return "SEHFinallyStmt"; + case CXCursor_MSAsmStmt: return "MSAsmStmt"; + case CXCursor_NullStmt: return "NullStmt"; + case CXCursor_DeclStmt: return "DeclStmt"; + case CXCursor_LastStmt: return "LastStmt"; + case CXCursor_TranslationUnit: return "TranslationUnit"; + //case CXCursor_FirstAttr: return "FirstAttr"; + case CXCursor_UnexposedAttr: return "UnexposedAttr"; + case CXCursor_IBActionAttr: return "IBActionAttr"; + case CXCursor_IBOutletAttr: return "IBOutletAttr"; + case CXCursor_IBOutletCollectionAttr: return "IBOutletCollectionAttr"; + case CXCursor_CXXFinalAttr: return "CXXFinalAttr"; + case CXCursor_CXXOverrideAttr: return "CXXOverrideAttr"; + case CXCursor_AnnotateAttr: return "AnnotateAttr"; + case CXCursor_AsmLabelAttr: return "AsmLabelAttr"; + case CXCursor_LastAttr: return "LastAttr"; + case CXCursor_PreprocessingDirective: return "PreprocessingDirective"; + case CXCursor_MacroDefinition: return "MacroDefinition"; + case CXCursor_MacroExpansion: return "MacroExpansion"; + //case CXCursor_MacroInstantiation: return "MacroInstantiation"; + case CXCursor_InclusionDirective: return "InclusionDirective"; + //case CXCursor_FirstPreprocessing: return "FirstPreprocessing"; + //case CXCursor_LastPreprocessing: return "LastPreprocessing"; + case CXCursor_ModuleImportDecl: return "ModuleImportDecl"; + //case CXCursor_FirstExtraDecl: return "FirstExtraDecl"; + case CXCursor_LastExtraDecl: return "LastExtraDecl"; + } + return ""; +} diff --git a/libclangmm/Utility.h b/libclangmm/Utility.h new file mode 100644 index 00000000..de234b1d --- /dev/null +++ b/libclangmm/Utility.h @@ -0,0 +1,11 @@ +#ifndef UTILITY_H_ +#define UTILITY_H_ +#include +#include + +namespace clang { + std::string to_string(CXString cx_string); + std::string to_string(CXCursorKind cursor_kind); +} + +#endif // UTILITY_H_ \ No newline at end of file diff --git a/libclangmm/clangmm.h b/libclangmm/clangmm.h new file mode 100644 index 00000000..b1abb81c --- /dev/null +++ b/libclangmm/clangmm.h @@ -0,0 +1,17 @@ +#ifndef CLANGMM_H_ +#define CLANGMM_H_ +#include "TranslationUnit.h" +#include "SourceLocation.h" +#include "SourceRange.h" +#include "Token.h" +#include "Tokens.h" +#include "CompilationDatabase.h" +#include "CompileCommands.h" +#include "CompileCommand.h" +#include "CodeCompleteResults.h" +#include "CompletionString.h" +#include "Index.h" +#include "Cursor.h" +#include "Diagnostic.h" +#include "Utility.h" +#endif // CLANGMM_H_ diff --git a/main.cpp b/main.cpp new file mode 100644 index 00000000..b0db84c6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,85 @@ +#include + +#include "libclangmm\clangmm.h" +#include "libclangmm\Utility.h" +//#include + +CXChildVisitResult visitPrint(CXCursor cursor0, CXCursor parent, CXClientData param) { + int* level = static_cast(param); + + clang::Cursor cursor(cursor0); + + for (int i = 0; i < *level; ++i) + std::cout << " "; + std::cout << cursor.get_spelling() << " " << clang::to_string(cursor.get_kind()) << std::endl; + + *level += 1; + clang_visitChildren(cursor0, &visitPrint, level); + *level -= 1; + + return CXChildVisitResult::CXChildVisit_Continue; +/* + echo " ".repeat(param.level), cursor.kind, " ", getSpelling(cursor) + + var visitParam : VisitPrintParam + visitParam.level = param.level + 1 + visitChildren(cursor, visitPrint, addr visitParam) + + return VisitResult.Continu +*/ +} + +int main(int argc, char** argv) { + /* + echo "Parsing ", filename + let index : libclang.CXIndex = libclang.createIndex(#[excludeDeclsFromPCH]# 0, #[displayDiagnostics]# 0) + + let translationUnit : libclang.CXTranslationUnit = + libclang.parseTranslationUnit(index, filename.cstring, nil, 0, nil, 0, 0) + if translationUnit == nil : + echo "Error: cannot create translation unit for '", filename, "'" + return + + let cursor = libclang.getTranslationUnitCursor(translationUnit) + + var param : VisitFileParam + param.db = db + + echo "=== START AST ===" + # printChildren(cursor, 0) + echo "=== DONE AST ===" + + var file : File + file.path = filename + file.vars = newList[VarRef]() + file.funcs = newList[FuncRef]() + file.types = newList[TypeRef]() + + visitChildren(cursor, visitFile, addr param) + + libclang.disposeTranslationUnit(translationUnit) + libclang.disposeIndex(index) + */ + + std::vector args; + + clang::Index index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/); + clang::TranslationUnit translationUnit(index, "test.cc", args); + + int level = 0; + auto cursor = clang_getTranslationUnitCursor(translationUnit.cx_tu); + clang_visitChildren(cursor, &visitPrint, &level); + /* + TranslationUnit(Index &index, + const std::string &file_path, + const std::vector &command_line_args, + const std::string &buffer, + unsigned flags = DefaultFlags()); + TranslationUnit(Index &index, + const std::string &file_path, + const std::vector &command_line_args, + unsigned flags = DefaultFlags()); + */ + + std::cin.get(); +} \ No newline at end of file diff --git a/test.cc b/test.cc new file mode 100644 index 00000000..818f97da --- /dev/null +++ b/test.cc @@ -0,0 +1,2 @@ +void bar() {} +void foo() {} \ No newline at end of file