diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a762326 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "external/type_safe"] + path = external/type_safe + url = https://github.com/foonathan/type_safe +[submodule "external/tiny-process-library"] + path = external/tiny-process-library + url = https://github.com/eidheim/tiny-process-library diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8a82471 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2017 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +cmake_minimum_required(VERSION 3.3) +project(cppast VERSION 0.0) + +# options +option(CPPAST_BUILD_TEST "whether or not to build the tests" ON) + +include(external/external.cmake) + +add_subdirectory(src) +if(CPPAST_BUILD_TEST) + add_subdirectory(test) +endif() + diff --git a/external/external.cmake b/external/external.cmake new file mode 100644 index 0000000..ce7453f --- /dev/null +++ b/external/external.cmake @@ -0,0 +1,163 @@ +# Copyright (C) 2017 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +# +# install type safe +# +find_package(type_safe QUIET) +if(NOT type_safe_FOUND) + message(STATUS "Installing type_safe via submodule") + execute_process(COMMAND git submodule update --init -- external/type_safe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/type_safe EXCLUDE_FROM_ALL) +endif() + +# +# install the tiny-process-library +# +message(STATUS "Installing tiny-process-library via submodule") +execute_process(COMMAND git submodule update --init -- external/tiny-process-library + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +find_package(Threads REQUIRED QUIET) + +# create a target here instead of using the one provided +set(tiny_process_dir ${CMAKE_CURRENT_SOURCE_DIR}/external/tiny-process-library) +if(WIN32) + add_library(_cppast_tiny_process EXCLUDE_FROM_ALL + ${tiny_process_dir}/process.hpp + ${tiny_process_dir}/process.cpp + ${tiny_process_dir}/process_win.cpp) +else() + add_library(_cppast_tiny_process EXCLUDE_FROM_ALL + ${tiny_process_dir}/process.hpp + ${tiny_process_dir}/process.cpp + ${tiny_process_dir}/process_unix.cpp) +endif() +target_include_directories(_cppast_tiny_process PUBLIC ${tiny_process_dir}) +target_link_libraries(_cppast_tiny_process PUBLIC Threads::Threads) +set_target_properties(_cppast_tiny_process PROPERTIES CXX_STANDARD 11) + +# +# install libclang +# + +# downloads and extracts LLVM using the given version and OS name +# sets: LLVM_DOWNLOAD_DIR +function(_cppast_download_llvm version os) + set(folder "clang+llvm-${version}-${os}") # name of downloaded folder + + if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${folder}) + set(url http://releases.llvm.org/${version}/${folder}.tar.xz) # download URL + message(STATUS "Downloading LLVM from ${url}") + file(DOWNLOAD ${url} ${CMAKE_CURRENT_BINARY_DIR}/${folder}.tar.xz SHOW_PROGRESS + STATUS status + LOG log) + + list(GET status 0 status_code) + list(GET status 1 status_string) + if(NOT status_code EQUAL 0) + message(FATAL_ERROR "error downloading llvm: ${status_string}" "${log}") + endif() + + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xJf ${folder}.tar.xz + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + set(LLVM_DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${folder} PARENT_SCOPE) +endfunction() + +# finds the llvm-config binary +# sets: LLVM_CONFIG_BINARY +function(_cppast_find_llvm_config) + unset(LLVM_CONFIG_BINARY CACHE) + if (LLVM_DOWNLOAD_DIR) + find_program(LLVM_CONFIG_BINARY "llvm-config" "${LLVM_DOWNLOAD_DIR}/bin" NO_DEFAULT_PATH) + else() + find_program(LLVM_CONFIG_BINARY "llvm-config") + endif() + if(NOT LLVM_CONFIG_BINARY) + message(FATAL_ERROR "Unable to find llvm-config binary, please set option LLVM_CONFIG_BINARY yourself") + else() + message(STATUS "Found llvm-config at ${LLVM_CONFIG_BINARY}") + endif() +endfunction() + +# find libclang using the config tool +# sets: LIBCLANG_INCLUDE_DIR, LIBCLANG_SYSTEM_INCLUDE_DIR, LIBCLANG_LIBRARY and CLANG_BINARY +function(_cppast_find_libclang config_tool min_version force) + # check version + execute_process(COMMAND ${LLVM_CONFIG_BINARY} --version + OUTPUT_VARIABLE llvm_version OUTPUT_STRIP_TRAILING_WHITESPACE) + if(llvm_version VERSION_LESS min_version) + message(FATAL_ERROR "Outdated LLVM version ${llvm_version}, minimal supported is ${min_version}") + else() + message(STATUS "Using LLVM version ${llvm_version}") + endif() + + # get include directory + if(${force}) + unset(LIBCLANG_INCLUDE_DIR CACHE) + endif() + if(NOT LIBCLANG_INCLUDE_DIR) + execute_process(COMMAND ${config_tool} --includedir + OUTPUT_VARIABLE llvm_include_dir OUTPUT_STRIP_TRAILING_WHITESPACE) + find_path(LIBCLANG_INCLUDE_DIR "clang-c/Index.h" "${llvm_include_dir}" NO_DEFAULT_PATH) + message(STATUS "Found libclang header files at ${LIBCLANG_INCLUDE_DIR}") + endif() + + # find libclang library in llvm_library_dir + if(${force}) + unset(LIBCLANG_LIBRARY CACHE) + endif() + if(NOT LIBCLANG_LIBRARY) + execute_process(COMMAND ${config_tool} --libdir + OUTPUT_VARIABLE llvm_library_dir OUTPUT_STRIP_TRAILING_WHITESPACE) + find_library(LIBCLANG_LIBRARY "clang" "${llvm_library_dir}" NO_DEFAULT_PATH) + message(STATUS "Found libclang library at ${LIBCLANG_LIBRARY}") + endif() + + # find system header files in llvm_library_dir + if(${force}) + unset(LIBCLANG_SYSTEM_INCLUDE_DIR CACHE) + endif() + if(NOT LIBCLANG_SYSTEM_INCLUDE_DIR) + find_path(LIBCLANG_SYSTEM_INCLUDE_DIR "stddef.h" "${llvm_library_dir}/clang/${llvm_version}/include" NO_DEFAULT_PATH) + message(STATUS "Found libclang system header files at ${LIBCLANG_SYSTEM_INCLUDE_DIR}") + endif() + + # find clang binary in llvm_binary_dir + if(${force}) + unset(CLANG_BINARY CACHE) + endif() + if(NOT CLANG_BINARY) + execute_process(COMMAND ${config_tool} --bindir + OUTPUT_VARIABLE llvm_binary_dir OUTPUT_STRIP_TRAILING_WHITESPACE) + find_program(CLANG_BINARY "clang" "${llvm_binary_dir}" NO_DEFAULT_PATH) + message(STATUS "Found clang binary at ${CLANG_BINARY}") + endif() +endfunction() + +# create libclang target +# target: _cppast_libclang +function(_cppast_create_libclang_target library_path include_path) + add_library(_cppast_libclang SHARED IMPORTED) + set_target_properties(_cppast_libclang PROPERTIES + IMPORTED_LOCATION ${library_path} + INTERFACE_INCLUDE_DIRECTORIES ${include_path}) +endfunction() + +set(llvm_min_version 3.9.1) +set(LLVM_PREFERRED_VERSION 4.0.0 CACHE STRING "the preferred LLVM version") + +if(NOT DEFINED LLVM_CONFIG_BINARY) + if(DEFINED LLVM_DOWNLOAD_OS_NAME) + _cppast_download_llvm(${LLVM_PREFERRED_VERSION} ${LLVM_DOWNLOAD_OS_NAME}) + endif() + _cppast_find_llvm_config() + _cppast_find_libclang(${LLVM_CONFIG_BINARY} ${llvm_min_version} 1) # override here +else() + _cppast_find_libclang(${LLVM_CONFIG_BINARY} ${llvm_min_version} 0) +endif() + +_cppast_create_libclang_target(${LIBCLANG_LIBRARY} ${LIBCLANG_INCLUDE_DIR}) diff --git a/external/tiny-process-library b/external/tiny-process-library new file mode 160000 index 0000000..876ce11 --- /dev/null +++ b/external/tiny-process-library @@ -0,0 +1 @@ +Subproject commit 876ce117e7c92458bd1322f39935f28419d87b20 diff --git a/external/type_safe b/external/type_safe new file mode 160000 index 0000000..55daabb --- /dev/null +++ b/external/type_safe @@ -0,0 +1 @@ +Subproject commit 55daabb898ebd3e29806c0f1ab4f3d0f8ae0e663 diff --git a/include/cppast/code_generator.hpp b/include/cppast/code_generator.hpp index fa7d00a..287df46 100644 --- a/include/cppast/code_generator.hpp +++ b/include/cppast/code_generator.hpp @@ -26,7 +26,7 @@ namespace cppast } /// \effects Creates it viewing the C string `str`. - constexpr string_view(const char* str) noexcept : str_(str), length_(std::strlen(str)) + string_view(const char* str) noexcept : str_(str), length_(std::strlen(str)) { } diff --git a/include/cppast/cpp_entity.hpp b/include/cppast/cpp_entity.hpp index 4273444..e54f605 100644 --- a/include/cppast/cpp_entity.hpp +++ b/include/cppast/cpp_entity.hpp @@ -85,7 +85,7 @@ namespace cppast /// \requires The comment must not be empty, if there is one. void set_comment(type_safe::optional comment) noexcept { - comment_ = std::move(comment.value_or("")); + comment_ = comment.value_or(""); } protected: diff --git a/include/cppast/parser.hpp b/include/cppast/parser.hpp index 1da2ae2..d5fb8ea 100644 --- a/include/cppast/parser.hpp +++ b/include/cppast/parser.hpp @@ -13,7 +13,7 @@ namespace cppast { class cpp_entity_index; - class diagnostic; + struct diagnostic; /// Base class for a [cppast::diagnostic]() logger. /// diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..cb3da32 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,100 @@ +# Copyright (C) 2017 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +set(detail_header + ../include/cppast/detail/assert.hpp + ../include/cppast/detail/intrusive_list.hpp) +set(header + ../include/cppast/code_generator.hpp + ../include/cppast/compile_config.hpp + ../include/cppast/cpp_alias_template.hpp + ../include/cppast/cpp_array_type.hpp + ../include/cppast/cpp_class.hpp + ../include/cppast/cpp_class_template.hpp + ../include/cppast/cpp_decltype_type.hpp + ../include/cppast/cpp_entity.hpp + ../include/cppast/cpp_entity.hpp + ../include/cppast/cpp_entity_container.hpp + ../include/cppast/cpp_entity_index.hpp + ../include/cppast/cpp_entity_kind.hpp + ../include/cppast/cpp_entity_ref.hpp + ../include/cppast/cpp_enum.hpp + ../include/cppast/cpp_expression.hpp + ../include/cppast/cpp_file.hpp + ../include/cppast/cpp_forward_declarable.hpp + ../include/cppast/cpp_function.hpp + ../include/cppast/cpp_function_template.hpp + ../include/cppast/cpp_function_type.hpp + ../include/cppast/cpp_language_linkage.hpp + ../include/cppast/cpp_member_function.hpp + ../include/cppast/cpp_member_variable.hpp + ../include/cppast/cpp_namespace.hpp + ../include/cppast/cpp_preprocessor.hpp + ../include/cppast/cpp_storage_class_specifiers.hpp + ../include/cppast/cpp_template.hpp + ../include/cppast/cpp_template_parameter.hpp + ../include/cppast/cpp_type.hpp + ../include/cppast/cpp_type_alias.hpp + ../include/cppast/cpp_variable.hpp + ../include/cppast/cpp_variable_base.hpp + ../include/cppast/cpp_variable_template.hpp + ../include/cppast/diagnostic.hpp + ../include/cppast/libclang_parser.hpp + ../include/cppast/parser.hpp + ../include/cppast/visitor.hpp) +set(source + code_generator.cpp + cpp_alias_template.cpp + cpp_class.cpp + cpp_class_template.cpp + cpp_entity.cpp + cpp_entity_index.cpp + cpp_entity_kind.cpp + cpp_enum.cpp + cpp_expression.cpp + cpp_file.cpp + cpp_function.cpp + cpp_function_template.cpp + cpp_language_linkage.cpp + cpp_member_function.cpp + cpp_member_variable.cpp + cpp_namespace.cpp + cpp_preprocessor.cpp + cpp_template_parameter.cpp + cpp_type.cpp + cpp_type_alias.cpp + cpp_variable.cpp + cpp_variable_template.cpp + parser.cpp + visitor.cpp) +set(libclang_source + libclang/class_parser.cpp + libclang/debug_helper.cpp + libclang/debug_helper.hpp + libclang/enum_parser.cpp + libclang/expression_parser.cpp + libclang/function_parser.cpp + libclang/language_linkage_parser.cpp + libclang/libclang_parser.cpp + libclang/libclang_visitor.hpp + libclang/namespace_parser.cpp + libclang/parse_error.hpp + libclang/parse_functions.cpp + libclang/parse_functions.hpp + libclang/preprocessor.cpp + libclang/preprocessor.hpp + libclang/raii_wrapper.hpp + libclang/template_parser.cpp + libclang/tokenizer.cpp + libclang/tokenizer.hpp + libclang/type_parser.cpp + libclang/variable_parser.cpp) + +add_library(cppast ${detail_header} ${header} ${source} ${libclang_source}) +target_include_directories(cppast PUBLIC ../include) +target_link_libraries(cppast PUBLIC type_safe _cppast_tiny_process _cppast_libclang) +target_compile_definitions(cppast PUBLIC + CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR="${LIBCLANG_SYSTEM_INCLUDE_DIR}" + CPPAST_CLANG_BINARY="${CLANG_BINARY}") +set_target_properties(cppast PROPERTIES CXX_STANDARD 11) diff --git a/src/libclang/libclang_parser.cpp b/src/libclang/libclang_parser.cpp index a87b269..fb74a76 100644 --- a/src/libclang/libclang_parser.cpp +++ b/src/libclang/libclang_parser.cpp @@ -30,8 +30,8 @@ const std::vector& detail::libclang_compile_config_access::flags( libclang_compile_config::libclang_compile_config() : compile_config({}) { - set_clang_binary("clang++"); - add_include_dir(LIBCLANG_SYSTEM_INCLUDE_DIR); + set_clang_binary(CPPAST_CLANG_BINARY); + add_include_dir(CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR); } void libclang_compile_config::do_set_flags(cpp_standard standard, diff --git a/src/libclang/parse_functions.cpp b/src/libclang/parse_functions.cpp index 2064378..82aea52 100644 --- a/src/libclang/parse_functions.cpp +++ b/src/libclang/parse_functions.cpp @@ -80,7 +80,7 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co case CXCursor_UnexposedDecl: // go through all the try_parse_XXX functions if (auto entity = try_parse_cpp_language_linkage(context, cur)) - return std::move(entity); + return entity; break; case CXCursor_Namespace: diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index c309c5e..4102a5b 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -154,7 +154,7 @@ namespace std::unique_ptr make_cv_qualified(std::unique_ptr entity, cpp_cv cv) { if (cv == cpp_cv_none) - return std::move(entity); + return entity; return cpp_cv_qualified_type::build(std::move(entity), cv); } @@ -285,7 +285,7 @@ namespace std::unique_ptr make_ref_qualified(std::unique_ptr type, cpp_reference ref) { if (ref == cpp_ref_none) - return std::move(type); + return type; return cpp_reference_type::build(std::move(type), ref); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..e070c76 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2017 Jonathan Müller +# This file is subject to the license terms in the LICENSE file +# found in the top-level directory of this distribution. + +# download catch +if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/catch.hpp) + file(DOWNLOAD https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp + ${CMAKE_CURRENT_BINARY_DIR}/catch.hpp) +endif() + +set(tests + code_generator.cpp + cpp_alias_template.cpp + cpp_class.cpp + cpp_class_template.cpp + cpp_enum.cpp + cpp_function.cpp + cpp_function_template.cpp + cpp_language_linkage.cpp + cpp_member_function.cpp + cpp_member_variable.cpp + cpp_namespace.cpp + cpp_preprocessor.cpp + cpp_template_parameter.cpp + cpp_type_alias.cpp + cpp_variable.cpp) + +add_executable(cppast_test test.cpp test_parser.hpp ${tests}) +target_include_directories(cppast_test PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(cppast_test PUBLIC cppast) +set_target_properties(cppast_test PROPERTIES CXX_STANDARD 11) + +enable_testing() +add_test(NAME test COMMAND cppast_test) diff --git a/test/test_parser.hpp b/test/test_parser.hpp index 6ba7073..e6fd852 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -60,7 +60,7 @@ private: --indent_; } - void do_write_token_seq(cppast::string_view tokens) + void do_write_token_seq(cppast::string_view tokens) override { if (was_newline_) {