From e10216f25475469fc250a4f375d48dc24b39eb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lien=20Sell=C3=A6g?= Date: Sat, 16 May 2015 12:32:42 +0200 Subject: [PATCH] Initial commit --- .gitignore | 7 ++ CMakeLists.txt | 7 ++ README.md | 93 ++++++++++++++ cmake/Modules/FindLibClang.cmake | 82 ++++++++++++ src/CMakeLists.txt | 52 ++++++++ src/CodeCompleteResults.cc | 39 ++++++ src/CodeCompleteResults.h | 23 ++++ src/CompilationDatabase.cc | 16 +++ src/CompilationDatabase.h | 20 +++ src/CompileCommand.cc | 28 +++++ src/CompileCommand.h | 16 +++ src/CompileCommands.cc | 23 ++++ src/CompileCommands.h | 20 +++ src/CompletionString.cc | 28 +++++ src/CompletionString.h | 41 ++++++ src/Cursor.cc | 10 ++ src/Cursor.h | 185 ++++++++++++++++++++++++++++ src/Index.cc | 7 ++ src/Index.h | 16 +++ src/SourceLocation.cc | 59 +++++++++ src/SourceLocation.h | 38 ++++++ src/SourceRange.cc | 17 +++ src/SourceRange.h | 22 ++++ src/Token.cc | 33 +++++ src/Token.h | 31 +++++ src/Tokens.cc | 22 ++++ src/Tokens.h | 19 +++ src/TranslationUnit.cc | 76 ++++++++++++ src/TranslationUnit.h | 47 +++++++ src/clangmm.h | 15 +++ tests/CMakeLists.txt | 35 ++++++ tests/CodeCompleteResults_H_Test.cc | 35 ++++++ tests/CompletionString_H_Test.cc | 44 +++++++ tests/Cursor_H_Test.cc | 19 +++ tests/Entry.cc | 2 + tests/SourceLocation_H_Test.cc | 43 +++++++ tests/Token_H_Test.cc | 23 ++++ tests/TranslationUnit_Test.cc | 24 ++++ tests/case/main.cpp | 7 ++ 39 files changed, 1324 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 cmake/Modules/FindLibClang.cmake create mode 100644 src/CMakeLists.txt create mode 100644 src/CodeCompleteResults.cc create mode 100644 src/CodeCompleteResults.h create mode 100644 src/CompilationDatabase.cc create mode 100644 src/CompilationDatabase.h create mode 100644 src/CompileCommand.cc create mode 100644 src/CompileCommand.h create mode 100644 src/CompileCommands.cc create mode 100644 src/CompileCommands.h create mode 100644 src/CompletionString.cc create mode 100644 src/CompletionString.h create mode 100644 src/Cursor.cc create mode 100644 src/Cursor.h create mode 100644 src/Index.cc create mode 100644 src/Index.h create mode 100644 src/SourceLocation.cc create mode 100644 src/SourceLocation.h create mode 100644 src/SourceRange.cc create mode 100644 src/SourceRange.h create mode 100644 src/Token.cc create mode 100644 src/Token.h create mode 100644 src/Tokens.cc create mode 100644 src/Tokens.h create mode 100644 src/TranslationUnit.cc create mode 100644 src/TranslationUnit.h create mode 100644 src/clangmm.h create mode 100644 tests/CMakeLists.txt create mode 100644 tests/CodeCompleteResults_H_Test.cc create mode 100644 tests/CompletionString_H_Test.cc create mode 100644 tests/Cursor_H_Test.cc create mode 100644 tests/Entry.cc create mode 100644 tests/SourceLocation_H_Test.cc create mode 100644 tests/Token_H_Test.cc create mode 100644 tests/TranslationUnit_Test.cc create mode 100644 tests/case/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b70d48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +* +./* +!.gitignore +!*.h +!*.cc +!CMakeLists.txt + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e0c3bf2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required (VERSION 2.8.4) +set(project_name clangmm) +project(${project_name}) +set(library_installation_path "/usr/local/lib/libclangmm/") +enable_testing() +add_subdirectory(src) +add_subdirectory(tests) diff --git a/README.md b/README.md new file mode 100644 index 0000000..f149ce6 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# libclangmm - An easy to use C++-wrapper for libclang # + +## About ## +This project is written by *cppit* as part of an bachelor thesis + +# Install # +This section describes how to install this library on your system. The section below is tested in on unix based systems and in windows. If there are any problems please create an issue and we will look into it. +## Dependencies ## +Please install these dependencies on your system. + +* libclang +* cmake +* make +* clang or gcc (compiler) + +## Download the source ## +There are two ways of downloading the source + +### Download the zip ### +You can download the zip [here](https://github.com/cppit/libclangmm/archive/master.zip). + +### Cloning the repository ### + +``` +#!bash +$ git clone https://github.com/cppit/libclangmm.git + +``` + + +## Installation ## + +``` +#!sh +cmake . +make install +``` +**Notice:** *make install* needs root privileges + +# Usage # +One quick start: + +``` +#!c++ + // lets say it is empty + std::string path("your file here"); + + clang::Index index(0, 0); + clang::TranslationUnit tu(&index, path); + + // ReparseTranslationUnit takes a map with filepath as key + // and buffer as value + std::map buffers; + + // create buffer (this would normally be a gtk/qt-buffer or something) + std::string file; + file.append("#include "); + file.append("int main(int argc, char *argv[]) {\n"); + file.append("std::cout << \"Hello World!\" << std::endl;\n"); + file.append("return 0\n"); + file.append("}"); + + buffers[path] = file; + + // after you can use various methods to get locations + // for tokens for syntax highlighting of refactoring + + // the buffer map should contain all open files. I.e in an text editor + // you could have more than one file open at the same time. Putting the + // files in this std::map will make the translationunit be reparsed + // from memory instead of from file. + tu.ReparseTranslationUnit(path, buffers); + + // zero is the start of the buffer + clang::SourceLocation start(&tu, path, 0); + + // the 129 value is arbitrary, you must set it to the size of your + // buffer (the number of chars in the buffer) + clang::SourceLocation end(&tu, path, 129); + + clang::SourceRange range(&start, &end); + clang::Tokens tokens(&tu, &range); + + // now tokens are stored in "tokens" we can extract ranges that are + // comments for instance + std::vector ranges; + for (auto &t : tokens.tokens()) { + if (t.kind() == clang::Token_Comment) { + ranges.emplace_back(&tu, &t); + } + } +``` +For more examples see tests/ \ No newline at end of file diff --git a/cmake/Modules/FindLibClang.cmake b/cmake/Modules/FindLibClang.cmake new file mode 100644 index 0000000..8a4ed46 --- /dev/null +++ b/cmake/Modules/FindLibClang.cmake @@ -0,0 +1,82 @@ +# +# Try to find libclang +# +# Once done this will define: +# - 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. + +# most recent versions come first +set(LIBCLANG_KNOWN_LLVM_VERSIONS 3.6 + 3.5.1 + 3.5.0 #Arch Linux + 3.5 #LLVM Debian/Ubuntu packages from http://llvm.org/apt/ + 3.4.2 3.4.1 3.4 3.3 3.2 3.1) + +set(libclang_llvm_header_search_paths) +set(libclang_llvm_lib_search_paths + # LLVM Fedora + /usr/lib/llvm + ) + +foreach (version ${LIBCLANG_KNOWN_LLVM_VERSIONS}) + list(APPEND libclang_llvm_header_search_paths + # LLVM Debian/Ubuntu nightly packages: http://llvm.org/apt/ + "/usr/lib/llvm-${version}/include" + # LLVM MacPorts + "/opt/local/libexec/llvm-${version}/include" + # LLVM Homebrew + "/usr/local/Cellar/llvm/${version}/include" + # LLVM Homebrew/versions + "/usr/local/lib/llvm-${version}/include" + ) + + list(APPEND libclang_llvm_lib_search_paths + # LLVM Debian/Ubuntu nightly packages: http://llvm.org/apt/ + "/usr/lib/llvm-${version}/lib/" + # LLVM MacPorts + "/opt/local/libexec/llvm-${version}/lib" + # LLVM Homebrew + "/usr/local/Cellar/llvm/${version}/lib" + # LLVM Homebrew/versions + "/usr/local/lib/llvm-${version}/lib" + ) +endforeach() + +find_path(LIBCLANG_INCLUDE_DIR clang-c/Index.h + PATHS ${libclang_llvm_header_search_paths} + PATH_SUFFIXES LLVM/include #Windows package from http://llvm.org/releases/ + DOC "The path to the directory that contains clang-c/Index.h") + +# On Windows with MSVC, the import library uses the ".imp" file extension +# instead of the comon ".lib" +if (MSVC) + find_file(LIBCLANG_LIBRARY libclang.imp + PATH_SUFFIXES LLVM/lib + DOC "The file that corresponds to the libclang library.") +endif() + +find_library(LIBCLANG_LIBRARY NAMES libclang.imp libclang clang + PATHS ${libclang_llvm_lib_search_paths} + PATH_SUFFIXES LLVM/lib #Windows package from http://llvm.org/releases/ + DOC "The file that corresponds to the libclang library.") + +get_filename_component(LIBCLANG_LIBRARY_DIR ${LIBCLANG_LIBRARY} PATH) + +set(LIBCLANG_LIBRARIES ${LIBCLANG_LIBRARY}) +set(LIBCLANG_INCLUDE_DIRS ${LIBCLANG_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set LIBCLANG_FOUND to TRUE if +# all listed variables are TRUE +find_package_handle_standard_args(LibClang DEFAULT_MSG + LIBCLANG_LIBRARY LIBCLANG_INCLUDE_DIR) + +mark_as_advanced(LIBCLANG_INCLUDE_DIR LIBCLANG_LIBRARY) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..8e9259d --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,52 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +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 + ) +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 + ) + +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} + LIBRARY DESTINATION ${library_installation_path}) +install(FILES ${header_files} + DESTINATION ${library_installation_path}/include) \ No newline at end of file diff --git a/src/CodeCompleteResults.cc b/src/CodeCompleteResults.cc new file mode 100644 index 0000000..d72528b --- /dev/null +++ b/src/CodeCompleteResults.cc @@ -0,0 +1,39 @@ +#include "CodeCompleteResults.h" +#include "CompletionString.h" + +clang::CodeCompleteResults:: +CodeCompleteResults(clang::TranslationUnit *tu, + const std::string &file_name, + const std::map &buffers, + int line_num, + int column) { + 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); + } + results_ = clang_codeCompleteAt(tu->tu_, + file_name.c_str(), + line_num, + column, + files.data(), + files.size(), + clang_defaultCodeCompleteOptions()); + clang_sortCodeCompletionResults(results_->Results, results_->NumResults); +} + +int clang::CodeCompleteResults:: +size() { + return results_->NumResults; +} + +clang::CompletionString clang::CodeCompleteResults:: +get(int i) { + if (i > size()) { + // TODO(zalox) return type + } + return CompletionString(results_->Results[i].CompletionString); +} diff --git a/src/CodeCompleteResults.h b/src/CodeCompleteResults.h new file mode 100644 index 0000000..ef05d4c --- /dev/null +++ b/src/CodeCompleteResults.h @@ -0,0 +1,23 @@ +#ifndef CODECOMPLETERESULTS_H_ +#define CODECOMPLETERESULTS_H_ +#include +#include "TranslationUnit.h" + +namespace clang { + class CompletionString; + + class CodeCompleteResults { + public: + CodeCompleteResults(TranslationUnit *tu, + const std::string &file_name, + const std::map &buffers, + int line_num, + int column); + CompletionString get(int index); + int size(); + + private: + CXCodeCompleteResults *results_; + }; +} // namespace clang +#endif // CODECOMPLETERESULTS_H_ diff --git a/src/CompilationDatabase.cc b/src/CompilationDatabase.cc new file mode 100644 index 0000000..54ad121 --- /dev/null +++ b/src/CompilationDatabase.cc @@ -0,0 +1,16 @@ +#include "CompilationDatabase.h" +#include + +clang::CompilationDatabase:: +CompilationDatabase(const std::string &project_path) { + CXCompilationDatabase_Error error; + db_ = clang_CompilationDatabase_fromDirectory(project_path.c_str(), &error); + if(error) { + // TODO(user) error code... + } +} + +clang::CompilationDatabase:: +~CompilationDatabase() { + clang_CompilationDatabase_dispose(db_); +} diff --git a/src/CompilationDatabase.h b/src/CompilationDatabase.h new file mode 100644 index 0000000..8d66a57 --- /dev/null +++ b/src/CompilationDatabase.h @@ -0,0 +1,20 @@ +#ifndef COMPILATIONDATABASE_H_ +#define COMPILATIONDATABASE_H_ +#include +#include +#include + +namespace clang { + class CompileCommands; + class CompilationDatabase { + public: + explicit CompilationDatabase(const std::string &project_path); + CompilationDatabase(); + ~CompilationDatabase(); + private: + CXCompilationDatabase db_; + friend CompileCommands; + }; +} + +#endif // COMPILATIONDATABASE_H_ diff --git a/src/CompileCommand.cc b/src/CompileCommand.cc new file mode 100644 index 0000000..fd596b1 --- /dev/null +++ b/src/CompileCommand.cc @@ -0,0 +1,28 @@ +#include "CompileCommand.h" +#include "CompileCommands.h" +#include + +clang::CompileCommand:: +CompileCommand(int nth, clang::CompileCommands *commands) { + command_ = clang_CompileCommands_getCommand(commands->commands_, nth); +} + +std::string clang::CompileCommand:: +get_command() { + std::string res; + unsigned N = clang_CompileCommand_getNumArgs(command_); + for (int i = 0; i < N; i++) { + res += clang_getCString(clang_CompileCommand_getArg(command_, i)); + } + return res; +} + +std::vector clang::CompileCommand:: +get_command_as_args() { + unsigned N = clang_CompileCommand_getNumArgs(command_); + std::vector res(N); + for (int i = 0; i < N; i++) { + res[i] = clang_getCString(clang_CompileCommand_getArg(command_, i)); + } + return res; +} diff --git a/src/CompileCommand.h b/src/CompileCommand.h new file mode 100644 index 0000000..f56dac8 --- /dev/null +++ b/src/CompileCommand.h @@ -0,0 +1,16 @@ +#ifndef COMPILECOMMAND_H_ +#define COMPILECOMMAND_H_ +#include "CompilationDatabase.h" +#include + +namespace clang { + class CompileCommand { + public: + CompileCommand(int nth, CompileCommands *commands); + std::string get_command(); + std::vector get_command_as_args(); + private: + CXCompileCommand command_; + }; +} +#endif // COMPILECOMMAND_H_ diff --git a/src/CompileCommands.cc b/src/CompileCommands.cc new file mode 100644 index 0000000..15a0afd --- /dev/null +++ b/src/CompileCommands.cc @@ -0,0 +1,23 @@ +#include "CompileCommands.h" +#include + +clang::CompileCommands:: +CompileCommands(const std::string &filename, CompilationDatabase *db) { + commands_ = + clang_CompilationDatabase_getCompileCommands(db->db_, filename.c_str()); +} + +clang::CompileCommands:: +~CompileCommands() { + clang_CompileCommands_dispose(commands_); +} + +std::vector clang::CompileCommands:: +get_commands() { + unsigned N = clang_CompileCommands_getSize(commands_); + std::vector res; + for (auto i = 0; i < N; i++) { + res.emplace_back(clang::CompileCommand(i, this)); + } + return res; +} diff --git a/src/CompileCommands.h b/src/CompileCommands.h new file mode 100644 index 0000000..f56d859 --- /dev/null +++ b/src/CompileCommands.h @@ -0,0 +1,20 @@ +#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(); + private: + CXCompileCommands commands_; + friend class CompileCommand; + }; +} +#endif // COMPILECOMMANDS_H_ diff --git a/src/CompletionString.cc b/src/CompletionString.cc new file mode 100644 index 0000000..e7cf1b8 --- /dev/null +++ b/src/CompletionString.cc @@ -0,0 +1,28 @@ +#include "CompletionString.h" + +clang::CompletionString:: +CompletionString(const CXCompletionString &str) { + str_ = str; +} + +int clang::CompletionString:: +get_num_chunks() { + return clang_getNumCompletionChunks(str_); +} + +std::vector clang::CompletionString:: +get_chunks() { + std::vector res; + if (clang_getCompletionAvailability(str_) == CXAvailability_Available) { + for (auto i = 0; i < get_num_chunks(); i++) { + res.emplace_back(clang_getCString(clang_getCompletionChunkText(str_, i)), + static_cast + (clang_getCompletionChunkKind(str_, i))); + } + } + return res; +} + +clang::CompletionChunk:: +CompletionChunk(std::string chunk, clang::CompletionChunkKind kind) : + chunk_(chunk), kind_(kind) { } diff --git a/src/CompletionString.h b/src/CompletionString.h new file mode 100644 index 0000000..040c87a --- /dev/null +++ b/src/CompletionString.h @@ -0,0 +1,41 @@ +#ifndef COMPLETIONSTRING_H_ +#define COMPLETIONSTRING_H_ +#include +#include "CodeCompleteResults.h" + +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); + const std::string& chunk() const { return chunk_; } + const CompletionChunkKind& kind() const { return kind_; } + private: + std::string chunk_; + CompletionChunkKind kind_; + }; + + class CompletionString { + public: + std::vector get_chunks(); + int get_num_chunks(); + private: + explicit CompletionString(const CXCompletionString &str); + CXCompletionString str_; + friend CodeCompleteResults; + }; +} // namespace clang +#endif // COMPLETIONSTRING_H_ diff --git a/src/Cursor.cc b/src/Cursor.cc new file mode 100644 index 0000000..e6ab0b7 --- /dev/null +++ b/src/Cursor.cc @@ -0,0 +1,10 @@ +#include "Cursor.h" + +const clang::CursorKind clang::Cursor::kind() { + return (CursorKind) clang_getCursorKind(this->cursor_); +} + +clang::Cursor:: +Cursor(clang::TranslationUnit *tu, clang::SourceLocation *source_location) { + cursor_ = clang_getCursor(tu->tu_, source_location->location_); +} diff --git a/src/Cursor.h b/src/Cursor.h new file mode 100644 index 0000000..f7cd903 --- /dev/null +++ b/src/Cursor.h @@ -0,0 +1,185 @@ +#ifndef CURSOR_H_ +#define CURSOR_H_ +#include "TranslationUnit.h" +#include "SourceLocation.h" + +namespace clang { + enum class CursorKind { + UnexposedDecl = 1, + StructDecl = 2, + UnionDecl = 3, + ClassDecl = 4, + EnumDecl = 5, + FieldDecl = 6, + EnumConstantDecl = 7, + FunctionDecl = 8, + VarDecl = 9, + ParmDecl = 10, + ObjCInterfaceDecl = 11, + ObjCCategoryDecl = 12, + ObjCProtocolDecl = 13, + ObjCPropertyDecl = 14, + ObjCIvarDecl = 15, + ObjCInstanceMethodDecl = 16, + ObjCClassMethodDecl = 17, + ObjCImplementationDecl = 18, + ObjCCategoryImplDecl = 19, + TypedefDecl = 20, + CXXMethod = 21, + Namespace = 22, + LinkageSpec = 23, + Constructor = 24, + Destructor = 25, + ConversionFunction = 26, + TemplateTypeParameter = 27, + NonTypeTemplateParameter = 28, + TemplateTemplateParameter = 29, + FunctionTemplate = 30, + ClassTemplate = 31, + ClassTemplatePartialSpecialization = 32, + NamespaceAlias = 33, + UsingDirective = 34, + UsingDeclaration = 35, + TypeAliasDecl = 36, + ObjCSynthesizeDecl = 37, + ObjCDynamicDecl = 38, + CXXAccessSpecifier = 39, + FirstDecl = UnexposedDecl, + LastDecl = CXXAccessSpecifier, + FirstRef = 40, + ObjCSuperClassRef = 40, + ObjCProtocolRef = 41, + ObjCClassRef = 42, + TypeRef = 43, + CXXBaseSpecifier = 44, + TemplateRef = 45, + NamespaceRef = 46, + MemberRef = 47, + LabelRef = 48, + OverloadedDeclRef = 49, + VariableRef = 50, + LastRef = VariableRef, + FirstInvalid = 70, + InvalidFile = 70, + NoDeclFound = 71, + NotImplemented = 72, + InvalidCode = 73, + LastInvalid = InvalidCode, + FirstExpr = 100, + UnexposedExpr = 100, + DeclRefExpr = 101, + MemberRefExpr = 102, + CallExpr = 103, + ObjCMessageExpr = 104, + BlockExpr = 105, + IntegerLiteral = 106, + FloatingLiteral = 107, + ImaginaryLiteral = 108, + StringLiteral = 109, + CharacterLiteral = 110, + ParenExpr = 111, + UnaryOperator = 112, + ArraySubscriptExpr = 113, + BinaryOperator = 114, + CompoundAssignOperator = 115, + ConditionalOperator = 116, + CStyleCastExpr = 117, + CompoundLiteralExpr = 118, + InitListExpr = 119, + AddrLabelExpr = 120, + StmtExpr = 121, + GenericSelectionExpr = 122, + GNUNullExpr = 123, + CXXStaticCastExpr = 124, + CXXDynamicCastExpr = 125, + CXXReinterpretCastExpr = 126, + CXXConstCastExpr = 127, + CXXFunctionalCastExpr = 128, + CXXTypeidExpr = 129, + CXXBoolLiteralExpr = 130, + CXXNullPtrLiteralExpr = 131, + CXXThisExpr = 132, + CXXThrowExpr = 133, + CXXNewExpr = 134, + CXXDeleteExpr = 135, + UnaryExpr = 136, + ObjCStringLiteral = 137, + ObjCEncodeExpr = 138, + ObjCSelectorExpr = 139, + ObjCProtocolExpr = 140, + ObjCBridgedCastExpr = 141, + PackExpansionExpr = 142, + SizeOfPackExpr = 143, + LambdaExpr = 144, + ObjCBoolLiteralExpr = 145, + ObjCSelfExpr = 146, + LastExpr = ObjCSelfExpr, + FirstStmt = 200, + UnexposedStmt = 200, + LabelStmt = 201, + CompoundStmt = 202, + CaseStmt = 203, + DefaultStmt = 204, + IfStmt = 205, + SwitchStmt = 206, + WhileStmt = 207, + DoStmt = 208, + ForStmt = 209, + GotoStmt = 210, + IndirectGotoStmt = 211, + ContinueStmt = 212, + BreakStmt = 213, + ReturnStmt = 214, + GCCAsmStmt = 215, + AsmStmt = GCCAsmStmt, + ObjCAtTryStmt = 216, + ObjCAtCatchStmt = 217, + ObjCAtFinallyStmt = 218, + ObjCAtThrowStmt = 219, + ObjCAtSynchronizedStmt = 220, + ObjCAutoreleasePoolStmt = 221, + ObjCForCollectionStmt = 222, + CXXCatchStmt = 223, + CXXTryStmt = 224, + CXXForRangeStmt = 225, + SEHTryStmt = 226, + SEHExceptStmt = 227, + SEHFinallyStmt = 228, + MSAsmStmt = 229, + NullStmt = 230, + DeclStmt = 231, + LastStmt = DeclStmt, + TranslationUnit = 300, + FirstAttr = 400, + UnexposedAttr = 400, + IBActionAttr = 401, + IBOutletAttr = 402, + IBOutletCollectionAttr = 403, + CXXFinalAttr = 404, + CXXOverrideAttr = 405, + AnnotateAttr = 406, + AsmLabelAttr = 407, + LastAttr = AsmLabelAttr, + PreprocessingDirective = 500, + MacroDefinition = 501, + MacroExpansion = 502, + MacroInstantiation = MacroExpansion, + InclusionDirective = 503, + FirstPreprocessing = PreprocessingDirective, + LastPreprocessing = InclusionDirective, + ModuleImportDecl = 600, + FirstExtraDecl = ModuleImportDecl, + LastExtraDecl = ModuleImportDecl, + }; + + class Cursor { + public: + Cursor(TranslationUnit *tu, SourceLocation *source_location); + const CursorKind kind(); + private: + CXCursor cursor_; + friend SourceRange; + friend SourceLocation; + }; +} // namespace clang +#endif // CURSOR_H_ diff --git a/src/Index.cc b/src/Index.cc new file mode 100644 index 0000000..89c1313 --- /dev/null +++ b/src/Index.cc @@ -0,0 +1,7 @@ +#include "Index.h" + +clang::Index:: +Index(int excludeDeclarationsFromPCH, int displayDiagnostics) { + index_ = clang_createIndex(excludeDeclarationsFromPCH, + displayDiagnostics); +} diff --git a/src/Index.h b/src/Index.h new file mode 100644 index 0000000..f93feab --- /dev/null +++ b/src/Index.h @@ -0,0 +1,16 @@ +#ifndef INDEX_H_ +#define INDEX_H_ + +#include + +namespace clang { + class TranslationUnit; + class Index { + public: + Index(int excludeDeclarationsFromPCH, int displayDiagnostics); + private: + CXIndex index_; + friend TranslationUnit; + }; +} // namespace clang +#endif // INDEX_H_ diff --git a/src/SourceLocation.cc b/src/SourceLocation.cc new file mode 100644 index 0000000..36564df --- /dev/null +++ b/src/SourceLocation.cc @@ -0,0 +1,59 @@ +#include "SourceLocation.h" + +// // // // // // // // +// SourceLocation // +// // // // // // // // +clang::SourceLocation:: +SourceLocation(clang::TranslationUnit *tu, + const std::string &filename, + int line_number, + int line_offset) { + CXFile file = clang_getFile(tu->tu_, + filename.c_str()); + location_ = clang_getLocation(tu->tu_, + file, + line_number, + line_offset); + } + +clang::SourceLocation:: +SourceLocation(Cursor *cursor) { + location_ = clang_getCursorLocation(cursor->cursor_); +} + +clang::SourceLocation:: +SourceLocation(clang::SourceRange *range, bool start) { + location_ = start ? clang_getRangeStart(range->range_) : + clang_getRangeEnd(range->range_); +} + +clang::SourceLocation:: +SourceLocation(TranslationUnit *tu, + Token *token) { + location_ = clang_getTokenLocation(tu->tu_, + token->token_); +} + +clang::SourceLocation:: +SourceLocation(clang::TranslationUnit *tu, + const std::string &filepath, + int offset) { + CXFile file = clang_getFile(tu->tu_, + filepath.c_str()); + location_ = clang_getLocationForOffset(tu->tu_, + file, + offset); +} + +void clang::SourceLocation:: +get_location_info(std::string* path, + unsigned *line, + unsigned *column, + unsigned *offset) { + CXFile file; + clang_getExpansionLocation(location_, &file, line, column, offset); + if (path != NULL) { + path->operator=(((clang_getCString((clang_getFileName(file)))))); + } +} + diff --git a/src/SourceLocation.h b/src/SourceLocation.h new file mode 100644 index 0000000..e6cd3b0 --- /dev/null +++ b/src/SourceLocation.h @@ -0,0 +1,38 @@ +#ifndef SOURCELOCATION_H_ +#define SOURCELOCATION_H_ +#include "TranslationUnit.h" +#include "Token.h" +#include "Cursor.h" + +namespace clang { + class SourceLocation { + public: + SourceLocation(TranslationUnit* tu, + const std::string &filename, + int line_number, + int column); + + SourceLocation(TranslationUnit *tu, + Token *token); + + SourceLocation(SourceRange *range, bool start); + + SourceLocation(TranslationUnit *tu, + const std::string &filepath, + int offset); + + explicit SourceLocation(Cursor *cursor); + + void get_location_info(std::string* path, + unsigned *line, + unsigned *column, + unsigned *offset); + + private: + CXSourceLocation location_; + friend SourceRange; + friend Cursor; + }; + +} // namespace clang +#endif // SOURCELOCATION_H_ diff --git a/src/SourceRange.cc b/src/SourceRange.cc new file mode 100644 index 0000000..d6edc89 --- /dev/null +++ b/src/SourceRange.cc @@ -0,0 +1,17 @@ +#include "SourceRange.h" + +clang::SourceRange:: +SourceRange(clang::TranslationUnit *tu, clang::Token *token) { + range_ = clang_getTokenExtent(tu->tu_, token->token_); +} + +clang::SourceRange:: +SourceRange(clang::SourceLocation *start, clang::SourceLocation *end) { + range_ = clang_getRange(start->location_, end->location_); +} + +clang::SourceRange::~SourceRange() { } + +clang::SourceRange::SourceRange(Cursor *cursor) { + range_ = clang_getCursorExtent(cursor->cursor_); +} diff --git a/src/SourceRange.h b/src/SourceRange.h new file mode 100644 index 0000000..8cc9afe --- /dev/null +++ b/src/SourceRange.h @@ -0,0 +1,22 @@ +#ifndef SOURCERANGE_H_ +#define SOURCERANGE_H_ +#include "TranslationUnit.h" +#include "Token.h" +#include "Cursor.h" + +namespace clang { + class SourceRange { + public: + SourceRange(TranslationUnit *tu, Token *token); + SourceRange(SourceLocation *start, + SourceLocation *end); + explicit SourceRange(Cursor *cursor); + ~SourceRange(); + + private: + CXSourceRange range_; + friend Tokens; + friend SourceLocation; + }; +} // namespace clang +#endif // SOURCERANGE_H_ diff --git a/src/Token.cc b/src/Token.cc new file mode 100644 index 0000000..036d741 --- /dev/null +++ b/src/Token.cc @@ -0,0 +1,33 @@ +#include "Token.h" +#include + +// // // // // +// Token // +// // // // // + +// clang::Token instansiates an token +clang::Token::Token(const CXToken &token) : + token_(token) { +} + +// returns gets an source location for this token objekt +// based on the translationunit given +clang::SourceLocation clang::Token:: + get_source_location(clang::TranslationUnit *tu) { + return SourceLocation(tu, this); +} + +// returns a sourcerange that covers this token +clang::SourceRange clang::Token:: + get_source_range(clang::TranslationUnit *tu) { + return SourceRange(tu, this); +} +// returns a string description of this tokens kind +std::string clang::Token::get_token_spelling(clang::TranslationUnit *tu) { + CXString s = clang_getTokenSpelling(tu->tu_, token_); + return std::string(clang_getCString(s)); +} + +const clang::TokenKind clang::Token::kind() { + return (TokenKind) clang_getTokenKind(token_); +} diff --git a/src/Token.h b/src/Token.h new file mode 100644 index 0000000..6ff1ffc --- /dev/null +++ b/src/Token.h @@ -0,0 +1,31 @@ +#ifndef TOKEN_H_ +#define TOKEN_H_ +#include "SourceLocation.h" +#include "SourceRange.h" +#include "TranslationUnit.h" + +namespace clang { + enum TokenKind { + Token_Punctuation, + Token_Keyword, + Token_Identifier, + Token_Literal, + Token_Comment + }; + + class Token { + public: + const TokenKind kind(); + std::string get_token_spelling(TranslationUnit *tu); + SourceLocation get_source_location(TranslationUnit *tu); + SourceRange get_source_range(TranslationUnit *tu); + + private: + explicit Token(const CXToken &token); + friend SourceRange; + friend SourceLocation; + friend Tokens; + CXToken token_; + }; +} // namespace clang +#endif // TOKEN_H_ diff --git a/src/Tokens.cc b/src/Tokens.cc new file mode 100644 index 0000000..d824fb8 --- /dev/null +++ b/src/Tokens.cc @@ -0,0 +1,22 @@ +#include "Tokens.h" +#include +clang::Tokens::Tokens(clang::TranslationUnit *tu, clang::SourceRange *range) { + clang_tokenize(tu->tu_, + range->range_, + &tokens_, + &num_tokens_); + for (int i = 0; i < num_tokens_; i++) { + tks.push_back(clang::Token(tokens_[i])); + } +} + +clang::Tokens::~Tokens() { + // instead of using clang_disposeTokens() the implementation + // of the latter method is just free(token_) the same as + // delete(tokens_) eliminating the need of tu* + delete tokens_; +} + +std::vector& clang::Tokens::tokens() { + return tks; +} diff --git a/src/Tokens.h b/src/Tokens.h new file mode 100644 index 0000000..344b0a0 --- /dev/null +++ b/src/Tokens.h @@ -0,0 +1,19 @@ +#ifndef TOKENS_H_ +#define TOKENS_H_ +#include "TranslationUnit.h" +#include "SourceRange.h" +#include "Token.h" + +namespace clang { + class Tokens { + public: + Tokens(TranslationUnit *tu, SourceRange *range); + ~Tokens(); + std::vector& tokens(); + protected: + std::vector tks; + CXToken *tokens_; + unsigned num_tokens_; + }; +} // namespace clang +#endif // TOKENS_H_ diff --git a/src/TranslationUnit.cc b/src/TranslationUnit.cc new file mode 100644 index 0000000..dab7f20 --- /dev/null +++ b/src/TranslationUnit.cc @@ -0,0 +1,76 @@ +#include "TranslationUnit.h" + +clang::TranslationUnit:: +~TranslationUnit() { + clang_disposeTranslationUnit(tu_); +} + + +clang::TranslationUnit& clang::TranslationUnit:: +operator=(const clang::TranslationUnit &tu) { + tu_ = tu.tu_; + return *this; +} + +clang::TranslationUnit:: +TranslationUnit(Index *index, + const std::string &filepath, + const std::vector &command_line_args) { + tu_ = clang_createTranslationUnitFromSourceFile(index->index_, + filepath.c_str(), + command_line_args.size(), + command_line_args.data(), + 0, + NULL); +} + +clang::TranslationUnit:: +TranslationUnit(Index *index, + const std::string &filepath) { + tu_ = clang_createTranslationUnitFromSourceFile(index->index_, + filepath.c_str(), + 0, + NULL, + 0, + NULL); +} + +clang::TranslationUnit:: +TranslationUnit(clang::Index *index, + const std::string &filepath, + const std::vector &command_line_args, + const std::map &buffers) { + 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); + } + tu_ = + clang_parseTranslationUnit(index->index_, + filepath.c_str(), + command_line_args.data(), + command_line_args.size(), + files.data(), + files.size(), + clang_defaultEditingTranslationUnitOptions()); +} + +int clang::TranslationUnit:: +ReparseTranslationUnit(const std::string &file_path, + const std::map &buffers) { + 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); + } + return clang_reparseTranslationUnit(tu_, + files.size(), + files.data(), + clang_defaultReparseOptions(tu_)); +} diff --git a/src/TranslationUnit.h b/src/TranslationUnit.h new file mode 100644 index 0000000..3d0d5f1 --- /dev/null +++ b/src/TranslationUnit.h @@ -0,0 +1,47 @@ +#ifndef TRANSLATIONUNIT_H_ +#define TRANSLATIONUNIT_H_ +#include +#include +#include +#include +#include +#include +#include "Index.h" + +namespace clang { + class Token; + class Tokens; + class SourceLocation; + class SourceRange; + class Cursor; + class CodeCompleteResults; + + class TranslationUnit { + public: + TranslationUnit(Index *index, + const std::string &filepath, + const std::vector &command_line_args); + TranslationUnit(Index *index, + const std::string &filepath, + const std::vector &command_line_args, + const std::map &buffers); + TranslationUnit(Index *index, + const std::string &filepath); + ~TranslationUnit(); + TranslationUnit& operator=(const TranslationUnit &tu); + int ReparseTranslationUnit(const std::string &file_path, + const std::map + &buffers); + + private: + friend Token; + friend Tokens; + friend SourceLocation; + friend SourceRange; + friend Cursor; + friend CodeCompleteResults; + CXTranslationUnit tu_; + }; +} // namespace clang +#endif // TRANSLATIONUNIT_H_ + diff --git a/src/clangmm.h b/src/clangmm.h new file mode 100644 index 0000000..d5b11c5 --- /dev/null +++ b/src/clangmm.h @@ -0,0 +1,15 @@ +#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" +#endif // CLANGMM_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..01899af --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,35 @@ +set(project_tests ${project_name}_tests) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_HOME_DIRECTORY}/cmake/Modules/") + +ADD_DEFINITIONS(-DBOOST_TEST_STATIC_LINK) + +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) +find_package(Boost 1.55 COMPONENTS unit_test_framework system filesystem REQUIRED) + +add_executable(${project_tests} + Entry.cc + TranslationUnit_Test.cc + CompletionString_H_Test.cc + CodeCompleteResults_H_Test.cc + Cursor_H_Test.cc + Token_H_Test.cc + SourceLocation_H_Test.cc + ) + +include_directories(${LIBCLANG_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} "${CMAKE_SOURCE_DIR}/src") +target_link_libraries(${project_tests} ${LIBCLANG_LIBRARIES} ${Boost_LIBRARIES} clangmm) + +set(tests + ${project_tests} + ) + +add_test(${tests} ${tests}) \ No newline at end of file diff --git a/tests/CodeCompleteResults_H_Test.cc b/tests/CodeCompleteResults_H_Test.cc new file mode 100644 index 0000000..8912a90 --- /dev/null +++ b/tests/CodeCompleteResults_H_Test.cc @@ -0,0 +1,35 @@ +#include +#include "clangmm.h" +#include + +BOOST_AUTO_TEST_CASE(code_complete_results) { + + // [ Should be changed with mockery + + std::string path("./case/main.cpp"); + + clang::Index index(0, 0); + clang::TranslationUnit tu(&index, path); + + // ReparseTranslationUnit takes a map with filepath as key + // and buffer as value + std::map buffers; + + // create buffer + std::string file; + file.append("#include \n"); + file.append("int main(int argc, char *argv[]) {\n"); + file.append("std::string str;\n"); + file.append("str.\n"); + file.append("return 0\n"); + file.append("}"); + + buffers[path] = file; + + // ] + + clang::CodeCompleteResults results(&tu, path, buffers, 4, 5); + + BOOST_CHECK(results.size() == 105); + BOOST_CHECK(results.get(0).get_num_chunks() == 5); +} diff --git a/tests/CompletionString_H_Test.cc b/tests/CompletionString_H_Test.cc new file mode 100644 index 0000000..4f70843 --- /dev/null +++ b/tests/CompletionString_H_Test.cc @@ -0,0 +1,44 @@ +#include +#include "clangmm.h" +#include + +BOOST_AUTO_TEST_CASE(completion_chunk) { + clang::CompletionChunk str("(", clang::CompletionChunk_LeftBrace); + + BOOST_CHECK(str.chunk() == "("); + BOOST_CHECK(str.kind() == clang::CompletionChunk_LeftBrace); +} + +BOOST_AUTO_TEST_CASE(completion_string) { + + // [ Should be changed with mockery + + std::string path("./case/main.cpp"); + + clang::Index index(0, 0); + clang::TranslationUnit tu(&index, path); + + // ReparseTranslationUnit takes a map with filepath as key + // and buffer as value + std::map buffers; + + // create buffer + std::string file; + file.append("#include \n"); + file.append("int main(int argc, char *argv[]) {\n"); + file.append("std::string str;\n"); + file.append("str.\n"); + file.append("return 0\n"); + file.append("}"); + + buffers[path] = file; + + clang::CodeCompleteResults results(&tu, path, buffers, 4, 5); + + // ] + + clang::CompletionString str = results.get(0); + + BOOST_CHECK(str.get_num_chunks() == 5); + BOOST_CHECK(str.get_chunks().size() == 5); +} diff --git a/tests/Cursor_H_Test.cc b/tests/Cursor_H_Test.cc new file mode 100644 index 0000000..afe10ef --- /dev/null +++ b/tests/Cursor_H_Test.cc @@ -0,0 +1,19 @@ +#include +#include "clangmm.h" +#include + +BOOST_AUTO_TEST_CASE(cursor) { + // [ Should be changed with mockery + + std::string path("./case/main.cpp"); + + clang::Index index(0, 0); + clang::TranslationUnit tu(&index, path); + + // ] + + clang::SourceLocation location(&tu, path, 6, 4); + clang::Cursor cursor(&tu, &location); + + BOOST_CHECK(cursor.kind() == clang::CursorKind::ReturnStmt); +} diff --git a/tests/Entry.cc b/tests/Entry.cc new file mode 100644 index 0000000..6979bbb --- /dev/null +++ b/tests/Entry.cc @@ -0,0 +1,2 @@ +#define BOOST_TEST_MODULE clangmm_tests +#include diff --git a/tests/SourceLocation_H_Test.cc b/tests/SourceLocation_H_Test.cc new file mode 100644 index 0000000..776fcf7 --- /dev/null +++ b/tests/SourceLocation_H_Test.cc @@ -0,0 +1,43 @@ +#include +#include "clangmm.h" +#include + +BOOST_AUTO_TEST_CASE(source_location) { + std::string path("./case/main.cpp"); + + clang::Index index(0, 0); + + clang::TranslationUnit tu(&index, path); + clang::SourceLocation start(&tu, path, 0); + clang::SourceLocation end(&tu, path, 7, 1); + clang::SourceRange range(&start, &end); + clang::Tokens tokens(&tu, &range); + + clang::SourceRange token_range = tokens.tokens()[28].get_source_range(&tu); + + unsigned token_start_line, token_start_column, token_start_offset, + token_end_line, token_end_column, token_end_offset; + std::string token_start_path, token_end_path; + + clang::SourceLocation token_start(&token_range, true); + clang::SourceLocation token_end(&token_range, false); + + token_start.get_location_info(&token_start_path, + &token_start_line, + &token_start_column, + &token_start_offset); + + token_end.get_location_info(&token_end_path, + &token_end_line, + &token_end_column, + &token_end_offset); + + BOOST_CHECK(token_start_path == path); + BOOST_CHECK(token_start_line == 6); + BOOST_CHECK(token_start_column == 3); + BOOST_CHECK(token_start_offset == 103); + BOOST_CHECK(token_end_path == path); + BOOST_CHECK(token_end_line == 6); + BOOST_CHECK(token_end_column == 9); + BOOST_CHECK(token_end_offset == 109); +} diff --git a/tests/Token_H_Test.cc b/tests/Token_H_Test.cc new file mode 100644 index 0000000..0b166e2 --- /dev/null +++ b/tests/Token_H_Test.cc @@ -0,0 +1,23 @@ +#include +#include "clangmm.h" +#include + +BOOST_AUTO_TEST_CASE(token) { + std::string path("./case/main.cpp"); + + clang::Index index(0, 0); + + clang::TranslationUnit tu(&index, path); + clang::SourceLocation start(&tu, path, 0); + clang::SourceLocation end(&tu, path, 7, 1); + + clang::SourceRange range(&start, &end); + + clang::Tokens tokens(&tu, &range); + + BOOST_CHECK(tokens.tokens().size() == 32); + BOOST_CHECK(tokens.tokens()[1].kind() == clang::TokenKind::Token_Identifier); + + std::string str = tokens.tokens()[28].get_token_spelling(&tu); + BOOST_CHECK(str == "return"); +} diff --git a/tests/TranslationUnit_Test.cc b/tests/TranslationUnit_Test.cc new file mode 100644 index 0000000..408ab9b --- /dev/null +++ b/tests/TranslationUnit_Test.cc @@ -0,0 +1,24 @@ +#include +#include "clangmm.h" +#include +#include + +BOOST_AUTO_TEST_CASE(translation_unit) { + std::string path("./case/main.cpp"); + + clang::Index index(0, 0); + clang::TranslationUnit tu(&index, path); + + // ReparseTranslationUnit takes a map with filepath as key + // and buffer as value + std::map buffers; + + // create buffer + std::string file = "int main(int argc, char *argv[]) {\n"; + file.append("std::cout << \"Hello World!\" << std::endl;\n"); + file.append("return 0\n"); + file.append("}"); + + buffers[path] = file; + BOOST_CHECK(tu.ReparseTranslationUnit(path, buffers) == 0); +} diff --git a/tests/case/main.cpp b/tests/case/main.cpp new file mode 100644 index 0000000..e6de09b --- /dev/null +++ b/tests/case/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + std::cout << "Hello, World!" << std::endl; + return 0; +}