├── .clang-format ├── .github ├── issue_template.md └── workflows │ └── ci.yml ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── cmake └── CodeCoverage.cmake ├── example ├── CMakeLists.txt ├── README.md ├── ast_printer.cpp ├── comparison.cpp ├── documentation_generator.cpp ├── enum_category.cpp ├── enum_to_string.cpp ├── example_parser.hpp └── serialization.cpp ├── external ├── external.cmake └── tpl │ ├── CMakeLists.txt │ ├── process.cpp │ ├── process.hpp │ ├── process_unix.cpp │ └── process_win.cpp ├── include └── cppast │ ├── code_generator.hpp │ ├── compile_config.hpp │ ├── cpp_alias_template.hpp │ ├── cpp_array_type.hpp │ ├── cpp_attribute.hpp │ ├── cpp_class.hpp │ ├── cpp_class_template.hpp │ ├── cpp_concept.hpp │ ├── cpp_decltype_type.hpp │ ├── cpp_entity.hpp │ ├── cpp_entity_container.hpp │ ├── cpp_entity_index.hpp │ ├── cpp_entity_kind.hpp │ ├── cpp_entity_ref.hpp │ ├── cpp_enum.hpp │ ├── cpp_expression.hpp │ ├── cpp_file.hpp │ ├── cpp_forward_declarable.hpp │ ├── cpp_friend.hpp │ ├── cpp_function.hpp │ ├── cpp_function_template.hpp │ ├── cpp_function_type.hpp │ ├── cpp_language_linkage.hpp │ ├── cpp_member_function.hpp │ ├── cpp_member_variable.hpp │ ├── cpp_namespace.hpp │ ├── cpp_preprocessor.hpp │ ├── cpp_static_assert.hpp │ ├── cpp_storage_class_specifiers.hpp │ ├── cpp_template.hpp │ ├── cpp_template_parameter.hpp │ ├── cpp_token.hpp │ ├── cpp_type.hpp │ ├── cpp_type_alias.hpp │ ├── cpp_variable.hpp │ ├── cpp_variable_base.hpp │ ├── cpp_variable_template.hpp │ ├── cppast_fwd.hpp │ ├── detail │ ├── assert.hpp │ └── intrusive_list.hpp │ ├── diagnostic.hpp │ ├── diagnostic_logger.hpp │ ├── libclang_parser.hpp │ ├── parser.hpp │ └── visitor.hpp ├── src ├── CMakeLists.txt ├── code_generator.cpp ├── cpp_alias_template.cpp ├── cpp_attribute.cpp ├── cpp_class.cpp ├── cpp_class_template.cpp ├── cpp_concept.cpp ├── cpp_entity.cpp ├── cpp_entity_index.cpp ├── cpp_entity_kind.cpp ├── cpp_enum.cpp ├── cpp_expression.cpp ├── cpp_file.cpp ├── cpp_forward_declarable.cpp ├── cpp_friend.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_static_assert.cpp ├── cpp_template_parameter.cpp ├── cpp_token.cpp ├── cpp_type.cpp ├── cpp_type_alias.cpp ├── cpp_variable.cpp ├── cpp_variable_template.cpp ├── diagnostic_logger.cpp ├── libclang │ ├── class_parser.cpp │ ├── concept_parser.cpp │ ├── cxtokenizer.cpp │ ├── cxtokenizer.hpp │ ├── debug_helper.cpp │ ├── debug_helper.hpp │ ├── enum_parser.cpp │ ├── expression_parser.cpp │ ├── friend_parser.cpp │ ├── function_parser.cpp │ ├── language_linkage_parser.cpp │ ├── libclang_parser.cpp │ ├── libclang_visitor.hpp │ ├── namespace_parser.cpp │ ├── parse_error.hpp │ ├── parse_functions.cpp │ ├── parse_functions.hpp │ ├── preprocessor.cpp │ ├── preprocessor.hpp │ ├── raii_wrapper.hpp │ ├── template_parser.cpp │ ├── type_parser.cpp │ └── variable_parser.cpp └── visitor.cpp ├── test ├── CMakeLists.txt ├── code_generator.cpp ├── cpp_alias_template.cpp ├── cpp_attribute.cpp ├── cpp_class.cpp ├── cpp_class_template.cpp ├── cpp_concept.cpp ├── cpp_enum.cpp ├── cpp_friend.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_static_assert.cpp ├── cpp_template_parameter.cpp ├── cpp_token.cpp ├── cpp_type_alias.cpp ├── cpp_variable.cpp ├── integration.cpp ├── libclang_parser.cpp ├── parser.cpp ├── preprocessor.cpp ├── test.cpp ├── test_parser.hpp └── visitor.cpp └── tool ├── CMakeLists.txt └── main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | AccessModifierOffset: -4 2 | AlignAfterOpenBracket: Align 3 | AlignConsecutiveAssignments: true 4 | AlignConsecutiveDeclarations: true 5 | AlignEscapedNewlinesLeft: Right 6 | AlignOperands: true 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: false 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: Empty 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AlwaysBreakAfterReturnType: None 15 | AlwaysBreakBeforeMultilineStrings: false 16 | AlwaysBreakTemplateDeclarations: true 17 | BinPackArguments: true 18 | BinPackParameters: true 19 | BreakBeforeBraces: Custom 20 | BraceWrapping: 21 | AfterClass: true 22 | AfterControlStatement: true 23 | AfterEnum: true 24 | AfterFunction: true 25 | AfterNamespace: true 26 | AfterStruct: true 27 | AfterUnion: true 28 | AfterExternBlock: true 29 | BeforeCatch: true 30 | BeforeElse: true 31 | SplitEmptyFunction: false 32 | SplitEmptyRecord: false 33 | SplitEmptyNamespace: false 34 | BreakBeforeBinaryOperators: All 35 | BreakBeforeTernaryOperators: true 36 | BreakConstructorInitializers: BeforeColon 37 | BreakStringLiterals: false 38 | ColumnLimit: 100 39 | CompactNamespaces: true 40 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 41 | ConstructorInitializerIndentWidth: 0 42 | ContinuationIndentWidth: 4 43 | Cpp11BracedListStyle: true 44 | DerivePointerAlignment: false 45 | FixNamespaceComments: true 46 | IncludeBlocks: Preserve 47 | IndentCaseLabels: false 48 | IndentPPDirectives: AfterHash 49 | IndentWidth: 4 50 | IndentWrappedFunctionNames: true 51 | KeepEmptyLinesAtTheStartOfBlocks: false 52 | Language: Cpp 53 | MaxEmptyLinesToKeep: 1 54 | NamespaceIndentation: Inner 55 | PenaltyBreakBeforeFirstCallParameter: 19937 56 | PenaltyReturnTypeOnItsOwnLine: 19937 57 | PointerAlignment: Left 58 | ReflowComments: true 59 | SortIncludes: true 60 | SortUsingDeclarations: true 61 | SpaceAfterCStyleCast: false 62 | SpaceAfterTemplateKeyword: true 63 | SpaceBeforeAssignmentOperators: true 64 | SpaceBeforeParens: ControlStatements 65 | SpaceInEmptyParentheses: false 66 | SpacesBeforeTrailingComments: 1 67 | SpacesInAngles: false 68 | SpacesInCStyleCastParentheses: false 69 | SpacesInParentheses: false 70 | SpacesInSquareBrackets: false 71 | Standard: Cpp11 72 | TabWidth: 4 73 | UseTab: Never 74 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | * cppast version: 4 | * parser: `libclang_parser` 5 | * clang version: 6 | 7 | Explanation of the error. 8 | 9 | Input: 10 | 11 | ```cpp 12 | Minimal source code reproducing the error 13 | ``` 14 | 15 | Input flags: 16 | 17 | Output: 18 | 19 | 20 | 21 | ``` 22 | Output of `cppast -v ` 23 | ``` 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | # Here we're keeping on arbitrary LLVM version fixed and varying GCC. 6 | linux-gcc: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | image: 11 | # List: https://github.com/conan-io/conan-docker-tools 12 | - gcc10 13 | - gcc9 14 | - gcc8 15 | - gcc7 16 | - gcc6 17 | 18 | runs-on: ubuntu-latest 19 | container: 20 | image: conanio/${{matrix.image}} 21 | options: --user root 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | - name: Create Build Environment 26 | run: cmake -E make_directory build 27 | - name: Install libclang 28 | run: apt-get -qq update && apt-get install -y llvm clang libclang-dev 29 | - name: Install ninja 30 | run: type ninja || apt-get install -y ninja-build 31 | 32 | - name: Configure 33 | working-directory: build/ 34 | run: cmake -GNinja $GITHUB_WORKSPACE 35 | - name: Build 36 | working-directory: build/ 37 | run: cmake --build . 38 | - name: Test 39 | working-directory: build/ 40 | run: ctest --output-on-failure 41 | 42 | # Here we're varying the LLVM version and using its clang for compiling as well. 43 | linux-clang: 44 | strategy: 45 | fail-fast: false 46 | matrix: 47 | version: [7, 8, 9, 10] 48 | 49 | runs-on: ubuntu-latest 50 | container: 51 | # Just one of the newer images. 52 | image: conanio/gcc10 53 | options: --user root 54 | 55 | steps: 56 | - uses: actions/checkout@v2 57 | - name: Create Build Environment 58 | run: cmake -E make_directory build 59 | - name: Install libclang 60 | run: apt-get -qq update && apt-get install -y llvm-${{matrix.version}} clang-${{matrix.version}} libclang-${{matrix.version}}-dev 61 | - name: Install ninja 62 | run: type ninja || apt-get install -y ninja-build 63 | 64 | - name: Configure 65 | working-directory: build/ 66 | run: cmake -GNinja $GITHUB_WORKSPACE -DCMAKE_CXX_COMPILER=clang++-${{matrix.version}} 67 | - name: Build 68 | working-directory: build/ 69 | run: cmake --build . 70 | - name: Test 71 | working-directory: build/ 72 | run: ctest --output-on-failure 73 | 74 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | # SPDX-License-Identifier: MIT 3 | # found in the top-level directory of this distribution. 4 | 5 | cmake_minimum_required(VERSION 3.11) 6 | project(cppast VERSION 0.1.0) 7 | 8 | if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 9 | set(is_top_level_project TRUE) 10 | else() 11 | set(is_top_level_project FALSE) 12 | endif() 13 | 14 | # options 15 | option(CPPAST_BUILD_TEST "whether or not to build the tests" OFF) 16 | option(CPPAST_BUILD_EXAMPLE "whether or not to build the examples" OFF) 17 | option(CPPAST_BUILD_TOOL "whether or not to build the tool" OFF) 18 | 19 | if(${CPPAST_BUILD_TEST} OR ${is_top_level_project}) 20 | set(build_test ON) 21 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # for the self integration test 22 | else() 23 | set(build_test OFF) 24 | endif() 25 | 26 | if(${CPPAST_BUILD_EXAMPLE} OR ${is_top_level_project}) 27 | set(build_example ON) 28 | else() 29 | set(build_example OFF) 30 | endif() 31 | 32 | if(${CPPAST_BUILD_TOOL} OR ${is_top_level_project}) 33 | set(build_tool ON) 34 | else() 35 | set(build_tool OFF) 36 | endif() 37 | 38 | include(external/external.cmake) 39 | 40 | if(build_test AND CPPAST_TEST_GCOV AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")) 41 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 42 | include(CodeCoverage) 43 | APPEND_COVERAGE_COMPILER_FLAGS() 44 | endif() 45 | 46 | add_subdirectory(src) 47 | 48 | if(${build_test}) 49 | enable_testing() 50 | add_subdirectory(test) 51 | endif() 52 | if(${build_example}) 53 | add_subdirectory(example) 54 | endif() 55 | if(${build_tool}) 56 | add_subdirectory(tool) 57 | endif() 58 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | # SPDX-License-Identifier: MIT 3 | # found in the top-level directory of this distribution. 4 | 5 | function(_cppast_example name) 6 | add_executable(cppast_example_${name} ${name}.cpp example_parser.hpp) 7 | target_link_libraries(cppast_example_${name} PUBLIC cppast) 8 | endfunction() 9 | 10 | _cppast_example(ast_printer) 11 | _cppast_example(comparison) 12 | _cppast_example(documentation_generator) 13 | _cppast_example(enum_category) 14 | _cppast_example(enum_to_string) 15 | _cppast_example(serialization) 16 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # cppast - examples 2 | 3 | This directory contains example tools written using cppast. 4 | 5 | ***Note:** These are not meant to be production ready tools, just a proof of concept!* 6 | 7 | All example executables get a single parameter, 8 | which is the directory where a `compile_commands.json` file is located. 9 | This file is a compilation database, you can read more about it [here](https://clang.llvm.org/docs/JSONCompilationDatabase.html). 10 | CMake, for example, can generate on when the option `CMAKE_EXPORT_COMPILE_COMMANDS` is `ON`. 11 | 12 | The tools will parse each file in the database and process it. 13 | Output will be written to `stdout`. 14 | 15 | ## List of examples: 16 | 17 | ### `ast_printer.cpp` 18 | 19 | It is a very simplified implementation of the cppast tool, it will print an AST. 20 | This is the starting example, it showcases entity visitation. 21 | 22 | ### `documentation_generator.cpp` 23 | 24 | It is a very simplified documentation generator. 25 | This showcases usage of the `cppast::code_generator`. 26 | 27 | ### Attributes example 28 | 29 | * `comparison.cpp` 30 | * `documentation_generator.cpp` 31 | * `enum_category.cpp` 32 | * `enum_to_string.cpp` 33 | * `serialization.cpp` 34 | 35 | Those examples were created as a part of my talk [Fun With (User-Defined) Attributes](http://foonathan.net/meetingcpp2017.html). 36 | Check the talk video to learn more about them. 37 | -------------------------------------------------------------------------------- /example/ast_printer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | /// \file 5 | /// This is a very primitive version of the cppast tool. 6 | /// 7 | /// Given an input file it will print the AST. 8 | 9 | #include // visit() 10 | 11 | #include "example_parser.hpp" 12 | 13 | void print_ast(const cppast::cpp_file& file) 14 | { 15 | std::string prefix; 16 | // visit each entity in the file 17 | cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) { 18 | if (info.event == cppast::visitor_info::container_entity_exit) // exiting an old container 19 | prefix.pop_back(); 20 | else if (info.event == cppast::visitor_info::container_entity_enter) 21 | // entering a new container 22 | { 23 | std::cout << prefix << "'" << e.name() << "' - " << cppast::to_string(e.kind()) << '\n'; 24 | prefix += "\t"; 25 | } 26 | else // if (info.event == cppast::visitor_info::leaf_entity) // a non-container entity 27 | std::cout << prefix << "'" << e.name() << "' - " << cppast::to_string(e.kind()) << '\n'; 28 | }); 29 | } 30 | 31 | int main(int argc, char* argv[]) 32 | { 33 | return example_main(argc, argv, {}, &print_ast); 34 | } 35 | -------------------------------------------------------------------------------- /example/comparison.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | /// \file 5 | /// Generate equality comparisons. 6 | /// 7 | /// Given an input file, it will generate comparison operators for each class that has the 8 | /// [[generate::comparison]] attribute. 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "example_parser.hpp" 18 | 19 | // whether or not the token string contains the given token 20 | bool has_token(const cppast::cpp_token_string& str, const char* token) 21 | { 22 | auto iter = std::find_if(str.begin(), str.end(), 23 | [&](const cppast::cpp_token& tok) { return tok.spelling == token; }); 24 | return iter != str.end(); 25 | } 26 | 27 | // generates equality operator for a class 28 | void generate_op_equal(std::ostream& out, const cppast::cpp_class& c) 29 | { 30 | out << "inline bool operator==(const " << c.name() << "& lhs, const " << c.name() 31 | << "& rhs) {\n"; 32 | out << " return "; 33 | 34 | auto first = true; 35 | 36 | // compare bases 37 | for (auto& base : c.bases()) 38 | { 39 | if (cppast::has_attribute(base, "generate::transient")) 40 | // if they are not marked not to be compared 41 | continue; 42 | 43 | if (first) 44 | first = false; 45 | else 46 | out << " && "; 47 | out << "static_cast(lhs) == static_cast(rhs)\n"; 49 | } 50 | 51 | // compare members 52 | for (auto& member : c) 53 | if (member.kind() == cppast::cpp_entity_kind::member_variable_t 54 | && !cppast::has_attribute(member, "generate::transient")) 55 | { 56 | // generate comparison code for non-transient member variables 57 | if (first) 58 | first = false; 59 | else 60 | out << " && "; 61 | out << "lhs." << member.name() << " == " 62 | << "rhs." << member.name() << "\n"; 63 | } 64 | 65 | out << " ;\n"; 66 | out << "}\n\n"; 67 | } 68 | 69 | // generate non equality operator for a class 70 | void generate_op_non_equal(std::ostream& out, const cppast::cpp_class& c) 71 | { 72 | // just forwards 73 | out << "inline bool operator!=(const " << c.name() << "& lhs, const " << c.name() 74 | << "& rhs) {\n"; 75 | out << " return !(lhs == rhs);\n"; 76 | out << "}\n\n"; 77 | } 78 | 79 | // generate comparison operators for all classes in the file 80 | void generate_comparison(const cppast::cpp_file& file) 81 | { 82 | cppast::visit( 83 | file, 84 | [](const cppast::cpp_entity& e) { 85 | // only visit non-templated class definitions that have the attribute set 86 | return (!cppast::is_templated(e) && e.kind() == cppast::cpp_entity_kind::class_t 87 | && cppast::is_definition(e) && cppast::has_attribute(e, "generate::comparison")) 88 | // or all namespaces 89 | || e.kind() == cppast::cpp_entity_kind::namespace_t; 90 | }, 91 | [](const cppast::cpp_entity& e, const cppast::visitor_info& info) { 92 | if (e.kind() == cppast::cpp_entity_kind::class_t && !info.is_old_entity()) 93 | { 94 | // it is a new class 95 | auto& class_ = static_cast(e); 96 | auto& attribute = cppast::has_attribute(e, "generate::comparison").value(); 97 | 98 | // generate requested operators 99 | if (attribute.arguments()) 100 | { 101 | if (has_token(attribute.arguments().value(), "==")) 102 | generate_op_equal(std::cout, class_); 103 | if (has_token(attribute.arguments().value(), "!=")) 104 | generate_op_non_equal(std::cout, class_); 105 | } 106 | else 107 | { 108 | generate_op_equal(std::cout, class_); 109 | generate_op_non_equal(std::cout, class_); 110 | } 111 | } 112 | else if (e.kind() == cppast::cpp_entity_kind::namespace_t) 113 | { 114 | if (info.event == cppast::visitor_info::container_entity_enter) 115 | // open namespace 116 | std::cout << "namespace " << e.name() << " {\n\n"; 117 | else // if (info.event == cppast::visitor_info::container_entity_exit) 118 | // close namespace 119 | std::cout << "}\n"; 120 | } 121 | }); 122 | } 123 | 124 | int main(int argc, char* argv[]) 125 | { 126 | return example_main(argc, argv, {}, &generate_comparison); 127 | } 128 | -------------------------------------------------------------------------------- /example/enum_category.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | /// \file 5 | /// Generates enum category functions. 6 | /// 7 | /// Given an input file, it will generate definitions for functions marked with 8 | /// [[generate::enum_category(name)]]. The function takes an enumerator and will return true if it 9 | /// is marked with the same category. 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include // cpp_enum 16 | #include // cpp_function 17 | #include // visit() 18 | 19 | #include "example_parser.hpp" 20 | 21 | // returns whether or not the given enumerator has the given category 22 | bool is_category(const cppast::cpp_enum_value& e, const std::string& name) 23 | { 24 | if (auto attr = cppast::has_attribute(e, "generate::enum_category")) 25 | { 26 | // ... by looking for the token 27 | auto iter 28 | = std::find_if(attr.value().arguments().value().begin(), 29 | attr.value().arguments().value().end(), 30 | [&](const cppast::cpp_token& tok) { return tok.spelling == name; }); 31 | return iter != attr.value().arguments().value().end(); 32 | } 33 | else 34 | return false; 35 | } 36 | 37 | // returns the enum the parameter type refers to 38 | const cppast::cpp_enum& get_enum(const cppast::cpp_entity_index& index, 39 | const cppast::cpp_function_parameter& param) 40 | { 41 | auto& param_type = param.type(); 42 | // it is an enum 43 | assert(param_type.kind() == cppast::cpp_type_kind::user_defined_t); 44 | // lookup definition 45 | auto& definition = static_cast(param_type) 46 | .entity() 47 | .get(index)[0u] 48 | .get(); 49 | 50 | assert(definition.kind() == cppast::cpp_entity_kind::enum_t); 51 | return static_cast(definition); 52 | } 53 | 54 | // generates the function definitions 55 | void generate_enum_category(const cppast::cpp_entity_index& index, const cppast::cpp_file& file) 56 | { 57 | cppast::visit( 58 | file, 59 | [](const cppast::cpp_entity& e) { 60 | // only visit function declarations that have the attribute set 61 | return (e.kind() == cppast::cpp_entity_kind::function_t && !cppast::is_definition(e) 62 | && cppast::has_attribute(e, "generate::enum_category")) 63 | // or all namespaces 64 | || e.kind() == cppast::cpp_entity_kind::namespace_t; 65 | }, 66 | [&](const cppast::cpp_entity& e, const cppast::visitor_info& info) { 67 | if (e.kind() == cppast::cpp_entity_kind::function_t) 68 | { 69 | // a new function, generate implementation 70 | assert(info.is_new_entity()); 71 | 72 | auto category = cppast::has_attribute(e, "generate::enum_category") 73 | .value() 74 | .arguments() 75 | .value() 76 | .as_string(); 77 | 78 | auto& func = static_cast(e); 79 | // return type must be bool 80 | assert(func.return_type().kind() == cppast::cpp_type_kind::builtin_t 81 | && static_cast(func.return_type()) 82 | .builtin_type_kind() 83 | == cppast::cpp_bool); 84 | 85 | // single parameter... 86 | assert(std::next(func.parameters().begin()) == func.parameters().end()); 87 | auto& param = *func.parameters().begin(); 88 | auto& enum_ = get_enum(index, param); 89 | 90 | // generate function definition 91 | std::cout << "inline bool " << func.name() << "(" << cppast::to_string(param.type()) 92 | << " e) {\n"; 93 | 94 | // generate switch 95 | std::cout << " switch (e) {\n"; 96 | for (const auto& enumerator : enum_) 97 | { 98 | std::cout << " case " << enum_.name() << "::" << enumerator.name() << ":\n"; 99 | if (is_category(enumerator, category)) 100 | std::cout << " return true;\n"; 101 | else 102 | std::cout << " return false;\n"; 103 | } 104 | std::cout << " }\n"; 105 | 106 | std::cout << "}\n\n"; 107 | } 108 | else if (e.kind() == cppast::cpp_entity_kind::namespace_t) 109 | { 110 | if (info.event == cppast::visitor_info::container_entity_enter) 111 | // open namespace 112 | std::cout << "namespace " << e.name() << " {\n\n"; 113 | else // if (info.event == cppast::visitor_info::container_entity_exit) 114 | // close namespace 115 | std::cout << "}\n"; 116 | } 117 | }); 118 | } 119 | 120 | int main(int argc, char* argv[]) 121 | { 122 | cppast::cpp_entity_index index; 123 | return example_main(argc, argv, index, 124 | [&](const cppast::cpp_file& file) { generate_enum_category(index, file); }); 125 | } 126 | -------------------------------------------------------------------------------- /example/enum_to_string.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | /// \file 5 | /// Generates enum `to_string()` code. 6 | /// 7 | /// Given an input file, it will generate a to_string() function for all enums marked with 8 | /// [[generate::to_string]]. 9 | 10 | #include 11 | 12 | #include // cpp_enum 13 | #include // visit() 14 | 15 | #include "example_parser.hpp" 16 | 17 | void generate_to_string(const cppast::cpp_file& file) 18 | { 19 | cppast::visit( 20 | file, 21 | [](const cppast::cpp_entity& e) { 22 | // only visit enum definitions that have the attribute set 23 | return (e.kind() == cppast::cpp_entity_kind::enum_t && cppast::is_definition(e) 24 | && cppast::has_attribute(e, "generate::to_string")) 25 | // or all namespaces 26 | || e.kind() == cppast::cpp_entity_kind::namespace_t; 27 | }, 28 | [](const cppast::cpp_entity& e, const cppast::visitor_info& info) { 29 | if (e.kind() == cppast::cpp_entity_kind::enum_t && !info.is_old_entity()) 30 | { 31 | // a new enum, generate to string function 32 | auto& enum_ = static_cast(e); 33 | 34 | // write function header 35 | std::cout << "inline const char* to_string(const " << enum_.name() << "& e) {\n"; 36 | 37 | // generate switch 38 | std::cout << " switch (e) {\n"; 39 | for (const auto& enumerator : enum_) 40 | { 41 | std::cout << " case " << enum_.name() << "::" << enumerator.name() << ":\n"; 42 | 43 | // attribute can be used to override the string 44 | if (auto attr = cppast::has_attribute(enumerator, "generate::to_string")) 45 | std::cout << " return " << attr.value().arguments().value().as_string() 46 | << ";\n"; 47 | else 48 | std::cout << " return \"" << enumerator.name() << "\";\n"; 49 | } 50 | std::cout << " }\n"; 51 | 52 | std::cout << "}\n\n"; 53 | } 54 | else if (e.kind() == cppast::cpp_entity_kind::namespace_t) 55 | { 56 | if (info.event == cppast::visitor_info::container_entity_enter) 57 | // open namespace 58 | std::cout << "namespace " << e.name() << " {\n\n"; 59 | else // if (info.event == cppast::visitor_info::container_entity_exit) 60 | // close namespace 61 | std::cout << "}\n"; 62 | } 63 | }); 64 | } 65 | 66 | int main(int argc, char* argv[]) 67 | { 68 | return example_main(argc, argv, {}, &generate_to_string); 69 | } 70 | -------------------------------------------------------------------------------- /example/example_parser.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_EXAMPLE_PARSER_HPP_INCLUDED 5 | #define CPPAST_EXAMPLE_PARSER_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | // reads the database directory from the command line argument 12 | // parses all files in that directory 13 | // and invokes the callback for each of them 14 | template 15 | int example_main(int argc, char* argv[], const cppast::cpp_entity_index& index, Callback cb) 16 | try 17 | { 18 | if (argc != 2) 19 | { 20 | std::cerr << "usage: " << argv[0] << " \n"; 21 | return 1; 22 | } 23 | else 24 | { 25 | cppast::libclang_compilation_database database(argv[1]); // the compilation database 26 | 27 | // simple_file_parser allows parsing multiple files and stores the results for us 28 | cppast::simple_file_parser parser(type_safe::ref(index)); 29 | try 30 | { 31 | cppast::parse_database(parser, database); // parse all files in the database 32 | } 33 | catch (cppast::libclang_error& ex) 34 | { 35 | std::cerr << "fatal libclang error: " << ex.what() << '\n'; 36 | return 1; 37 | } 38 | 39 | if (parser.error()) 40 | // a non-fatal parse error 41 | // error has been logged to stderr 42 | return 1; 43 | 44 | for (auto& file : parser.files()) 45 | cb(file); 46 | } 47 | 48 | return 0; 49 | } 50 | catch (std::exception& ex) 51 | { 52 | std::cerr << ex.what() << '\n'; 53 | return 1; 54 | } 55 | 56 | #endif // CPPAST_EXAMPLE_PARSER_HPP_INCLUDED 57 | -------------------------------------------------------------------------------- /example/serialization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | /// \file 5 | /// Serialization code generation. 6 | /// 7 | /// Given an input file, it will generate a serialize() function for each class marked with 8 | /// [[generate::serialize]]. 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "example_parser.hpp" 18 | 19 | // whether or not a type is a C string, i.e. char pointer 20 | bool is_c_string(const cppast::cpp_type& type) 21 | { 22 | if (type.kind() != cppast::cpp_type_kind::pointer_t) 23 | return false; 24 | 25 | // get the pointee 26 | auto& pointee = cppast::remove_cv(static_cast(type).pointee()); 27 | if (pointee.kind() != cppast::cpp_type_kind::builtin_t) 28 | return false; 29 | 30 | // check the builtin type kind 31 | auto builtin = static_cast(pointee).builtin_type_kind(); 32 | return builtin == cppast::cpp_char || builtin == cppast::cpp_char16 33 | || builtin == cppast::cpp_char32 || builtin == cppast::cpp_wchar; 34 | } 35 | 36 | // generate a serialization call for a member 37 | void generate_serialize_member(std::ostream& out, const cppast::cpp_member_variable& member) 38 | { 39 | auto& type = cppast::remove_cv(member.type()); 40 | 41 | if (cppast::has_attribute(member, "generate::transient")) 42 | // don't serialize transient members 43 | return; 44 | else if (auto attr = cppast::has_attribute(member, "generate::serialize")) 45 | { 46 | // generate code as specified by the attributes 47 | out << " " << attr.value().arguments().value().as_string() << ";\n"; 48 | } 49 | else if (type.kind() == cppast::cpp_type_kind::builtin_t) 50 | { 51 | // generate hypothetical member function call for builtin types 52 | out << " s.serialize(obj." << member.name() << ");\n"; 53 | } 54 | else if (type.kind() == cppast::cpp_type_kind::user_defined_t) 55 | { 56 | // generate ADL call 57 | out << " serialize(s, obj." << member.name() << ");\n"; 58 | } 59 | else if (is_c_string(type)) 60 | { 61 | // generate another hypothetical member function call 62 | out << " s.serialize_string(obj." << member.name() << ");\n"; 63 | } 64 | else 65 | throw std::invalid_argument("cannot serialize member " + member.name()); 66 | } 67 | 68 | // generate serialization function 69 | void generate_serialize(const cppast::cpp_file& file) 70 | { 71 | cppast::visit( 72 | file, 73 | [](const cppast::cpp_entity& e) { 74 | // only visit non-templated class definitions that have the attribute set 75 | return (!cppast::is_templated(e) && e.kind() == cppast::cpp_entity_kind::class_t 76 | && cppast::is_definition(e) && cppast::has_attribute(e, "generate::serialize")) 77 | // or all namespaces 78 | || e.kind() == cppast::cpp_entity_kind::namespace_t; 79 | }, 80 | [](const cppast::cpp_entity& e, const cppast::visitor_info& info) { 81 | if (e.kind() == cppast::cpp_entity_kind::class_t && !info.is_old_entity()) 82 | { 83 | auto& class_ = static_cast(e); 84 | 85 | std::cout << "inline void serialize(const foo::serializer& s, const " 86 | << class_.name() << "& obj) {\n"; 87 | 88 | // serialize base classes 89 | for (auto& base : class_.bases()) 90 | if (!cppast::has_attribute(base, "generate::transient")) 91 | std::cout << " serialize(s, static_cast(obj));\n"; 93 | 94 | // serialize member variables 95 | for (auto& member : class_) 96 | { 97 | if (member.kind() == cppast::cpp_entity_kind::member_variable_t) 98 | generate_serialize_member(std::cout, 99 | static_cast( 100 | member)); 101 | } 102 | 103 | std::cout << "}\n\n"; 104 | } 105 | else if (e.kind() == cppast::cpp_entity_kind::namespace_t) 106 | { 107 | if (info.event == cppast::visitor_info::container_entity_enter) 108 | // open namespace 109 | std::cout << "namespace " << e.name() << " {\n\n"; 110 | else // if (info.event == cppast::visitor_info::container_entity_exit) 111 | // close namespace 112 | std::cout << "}\n"; 113 | } 114 | }); 115 | } 116 | 117 | int main(int argc, char* argv[]) 118 | { 119 | return example_main(argc, argv, {}, generate_serialize); 120 | } 121 | -------------------------------------------------------------------------------- /external/tpl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | project(tiny-process-library) 4 | 5 | if(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") 6 | option(BUILD_TESTING "set ON to build library tests" ON) 7 | else() 8 | option(BUILD_TESTING "set ON to build library tests" OFF) 9 | endif() 10 | 11 | add_library(tiny-process-library process.cpp) 12 | add_library(tiny-process-library::tiny-process-library ALIAS tiny-process-library) 13 | 14 | if(MSVC) 15 | target_compile_definitions(tiny-process-library PRIVATE /D_CRT_SECURE_NO_WARNINGS) 16 | else() 17 | target_compile_options(tiny-process-library PRIVATE -std=c++11 -Wall -Wextra) 18 | endif() 19 | 20 | if(WIN32) 21 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 22 | target_sources(tiny-process-library PRIVATE process_win.cpp) 23 | #If compiled using MSYS2, use sh to run commands 24 | if(MSYS) 25 | target_compile_definitions(tiny-process-library PUBLIC MSYS_PROCESS_USE_SH) 26 | endif() 27 | else() 28 | target_sources(tiny-process-library PRIVATE process_unix.cpp) 29 | endif() 30 | 31 | find_package(Threads REQUIRED) 32 | 33 | target_link_libraries(tiny-process-library ${CMAKE_THREAD_LIBS_INIT}) 34 | target_include_directories(tiny-process-library PUBLIC $ 35 | $) 36 | 37 | # if tiny-process-library is not a sub-project: 38 | if(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") 39 | if(MSVC) 40 | add_definitions(/D_CRT_SECURE_NO_WARNINGS) 41 | else() 42 | add_compile_options(-std=c++11 -Wall -Wextra) 43 | endif() 44 | 45 | add_executable(examples examples.cpp) 46 | target_link_libraries(examples tiny-process-library) 47 | 48 | install(TARGETS tiny-process-library 49 | EXPORT ${PROJECT_NAME}-config 50 | ARCHIVE DESTINATION lib 51 | LIBRARY DESTINATION lib 52 | RUNTIME DESTINATION bin) 53 | 54 | install(EXPORT ${PROJECT_NAME}-config 55 | FILE ${PROJECT_NAME}-config.cmake 56 | NAMESPACE ${PROJECT_NAME}:: 57 | DESTINATION lib/cmake/${PROJECT_NAME} 58 | ) 59 | 60 | install(FILES process.hpp DESTINATION include) 61 | endif() 62 | 63 | if(BUILD_TESTING) 64 | enable_testing() 65 | add_subdirectory(tests) 66 | endif() 67 | -------------------------------------------------------------------------------- /external/tpl/process.cpp: -------------------------------------------------------------------------------- 1 | #include "process.hpp" 2 | 3 | namespace TinyProcessLib { 4 | 5 | Process::Process(const std::vector &arguments, const string_type &path, 6 | std::function read_stdout, 7 | std::function read_stderr, 8 | bool open_stdin, const Config &config) noexcept 9 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 10 | open(arguments, path); 11 | async_read(); 12 | } 13 | 14 | Process::Process(const string_type &command, const string_type &path, 15 | std::function read_stdout, 16 | std::function read_stderr, 17 | bool open_stdin, const Config &config) noexcept 18 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 19 | open(command, path); 20 | async_read(); 21 | } 22 | 23 | Process::Process(const std::vector &arguments, const string_type &path, 24 | const environment_type &environment, 25 | std::function read_stdout, 26 | std::function read_stderr, 27 | bool open_stdin, const Config &config) noexcept 28 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 29 | open(arguments, path, &environment); 30 | async_read(); 31 | } 32 | 33 | Process::Process(const string_type &command, const string_type &path, 34 | const environment_type &environment, 35 | std::function read_stdout, 36 | std::function read_stderr, 37 | bool open_stdin, const Config &config) noexcept 38 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 39 | open(command, path, &environment); 40 | async_read(); 41 | } 42 | 43 | Process::~Process() noexcept { 44 | close_fds(); 45 | } 46 | 47 | Process::id_type Process::get_id() const noexcept { 48 | return data.id; 49 | } 50 | 51 | bool Process::write(const std::string &str) { 52 | return write(str.c_str(), str.size()); 53 | } 54 | 55 | } // namespace TinyProcessLib 56 | -------------------------------------------------------------------------------- /include/cppast/cpp_alias_template.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ALIAS_TEMPLATE_HPP_INCLUDED 5 | #define CPPAST_CPP_ALIAS_TEMPLATE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_entity]() modelling a C++ alias template. 13 | class cpp_alias_template final : public cpp_template 14 | { 15 | public: 16 | static cpp_entity_kind kind() noexcept; 17 | 18 | /// Builder for [cppast::cpp_alias_template](). 19 | class builder : public basic_builder 20 | { 21 | public: 22 | using basic_builder::basic_builder; 23 | }; 24 | 25 | /// \returns A reference to the type alias that is being templated. 26 | const cpp_type_alias& type_alias() const noexcept 27 | { 28 | return static_cast(*begin()); 29 | } 30 | 31 | private: 32 | cpp_alias_template(std::unique_ptr alias) 33 | : cpp_template(std::unique_ptr(alias.release())) 34 | {} 35 | 36 | cpp_entity_kind do_get_entity_kind() const noexcept override; 37 | 38 | friend basic_builder; 39 | }; 40 | } // namespace cppast 41 | 42 | #endif // CPPAST_CPP_ALIAS_TEMPLATE_HPP_INCLUDED 43 | -------------------------------------------------------------------------------- /include/cppast/cpp_array_type.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ARRAY_TYPE_HPP_INCLUDED 5 | #define CPPAST_CPP_ARRAY_TYPE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// An array of a [cppast::cpp_type](). 13 | class cpp_array_type final : public cpp_type 14 | { 15 | public: 16 | /// \returns A newly created array. 17 | /// \notes `size` may be `nullptr`. 18 | static std::unique_ptr build(std::unique_ptr type, 19 | std::unique_ptr size) 20 | { 21 | return std::unique_ptr( 22 | new cpp_array_type(std::move(type), std::move(size))); 23 | } 24 | 25 | /// \returns A reference to the value [cppast::cpp_type](). 26 | const cpp_type& value_type() const noexcept 27 | { 28 | return *type_; 29 | } 30 | 31 | /// \returns An optional reference to the [cppast::cpp_expression]() that is the size of the 32 | /// array. \notes An unsized array - `T[]` - does not have a size. 33 | type_safe::optional_ref size() const noexcept 34 | { 35 | return type_safe::opt_cref(size_.get()); 36 | } 37 | 38 | private: 39 | cpp_array_type(std::unique_ptr type, std::unique_ptr size) 40 | : type_(std::move(type)), size_(std::move(size)) 41 | {} 42 | 43 | cpp_type_kind do_get_kind() const noexcept override 44 | { 45 | return cpp_type_kind::array_t; 46 | } 47 | 48 | std::unique_ptr type_; 49 | std::unique_ptr size_; 50 | }; 51 | } // namespace cppast 52 | 53 | #endif // CPPAST_CPP_ARRAY_TYPE_HPP_INCLUDED 54 | -------------------------------------------------------------------------------- /include/cppast/cpp_attribute.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ATTRIBUTE_HPP_INCLUDED 5 | #define CPPAST_CPP_ATTRIBUTE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace cppast 16 | { 17 | /// The known C++ attributes. 18 | enum class cpp_attribute_kind 19 | { 20 | // update get_attribute_kind() in tokenizer, when updating this 21 | 22 | alignas_, 23 | carries_dependency, 24 | deprecated, 25 | fallthrough, 26 | maybe_unused, 27 | nodiscard, 28 | noreturn, 29 | 30 | unknown, //< An unknown attribute. 31 | }; 32 | 33 | /// A C++ attribute, including `alignas` specifiers. 34 | /// 35 | /// It consists of a name, an optional namespace scope and optional arguments. 36 | /// The scope is just a single identifier and doesn't include the `::` and can be given explicitly 37 | /// or via using. The arguments are as specified in the source code but do not include the 38 | /// outer-most `(` and `)`. It can also be variadic or not. 39 | /// 40 | /// An attribute can be known or unknown. 41 | /// A known attribute will have the [cppast::cpp_attribute_kind]() set properly. 42 | class cpp_attribute 43 | { 44 | public: 45 | /// \effects Creates a known attribute, potentially with arguments. 46 | cpp_attribute(cpp_attribute_kind kind, type_safe::optional arguments); 47 | 48 | /// \effects Creates an unknown attribute giving it the optional scope, names, arguments and 49 | /// whether it is variadic. 50 | cpp_attribute(type_safe::optional scope, std::string name, 51 | type_safe::optional arguments, bool is_variadic) 52 | : scope_(std::move(scope)), arguments_(std::move(arguments)), name_(std::move(name)), 53 | variadic_(is_variadic) 54 | {} 55 | 56 | /// \returns The kind of attribute, if it is known. 57 | const cpp_attribute_kind& kind() const noexcept 58 | { 59 | return kind_; 60 | } 61 | 62 | /// \returns The name of the attribute. 63 | const std::string& name() const noexcept 64 | { 65 | return name_; 66 | } 67 | 68 | /// \returns The scope of the attribute, if there is any. 69 | const type_safe::optional& scope() const noexcept 70 | { 71 | return scope_; 72 | } 73 | 74 | /// \returns Whether or not the attribute is variadic. 75 | bool is_variadic() const noexcept 76 | { 77 | return variadic_; 78 | } 79 | 80 | /// \returns The arguments of the attribute, if they are any. 81 | const type_safe::optional& arguments() const noexcept 82 | { 83 | return arguments_; 84 | } 85 | 86 | private: 87 | type_safe::optional scope_; 88 | type_safe::optional arguments_; 89 | std::string name_; 90 | cpp_attribute_kind kind_ = cpp_attribute_kind::unknown; 91 | bool variadic_; 92 | }; 93 | 94 | /// A list of C++ attributes. 95 | using cpp_attribute_list = std::vector; 96 | 97 | /// Checks whether an attribute is given. 98 | /// \returns `true` if the given attribute list (1-2) / entity (3-4) contain 99 | /// an attribute of the given name (1+3) / kind (2+4). 100 | /// `false` otherwise. 101 | /// \group has_attribute 102 | type_safe::optional_ref has_attribute(const cpp_attribute_list& attributes, 103 | const std::string& name); 104 | 105 | /// \group has_attribute 106 | type_safe::optional_ref has_attribute(const cpp_attribute_list& attributes, 107 | cpp_attribute_kind kind); 108 | 109 | /// \group has_attribute 110 | type_safe::optional_ref has_attribute(const cpp_entity& e, 111 | const std::string& name); 112 | 113 | /// \group has_attribute 114 | type_safe::optional_ref has_attribute(const cpp_entity& e, 115 | cpp_attribute_kind kind); 116 | } // namespace cppast 117 | 118 | #endif // CPPAST_CPP_ATTRIBUTE_HPP_INCLUDED 119 | -------------------------------------------------------------------------------- /include/cppast/cpp_class_template.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_CLASS_TEMPLATE_HPP_INCLUDED 5 | #define CPPAST_CPP_CLASS_TEMPLATE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_entity]() modelling a class template. 13 | class cpp_class_template final : public cpp_template 14 | { 15 | public: 16 | static cpp_entity_kind kind() noexcept; 17 | 18 | /// Builder for [cppast::cpp_class_template](). 19 | class builder : public basic_builder 20 | { 21 | public: 22 | using basic_builder::basic_builder; 23 | }; 24 | 25 | /// A reference to the class that is being templated. 26 | const cpp_class& class_() const noexcept 27 | { 28 | return static_cast(*begin()); 29 | } 30 | 31 | private: 32 | cpp_class_template(std::unique_ptr func) 33 | : cpp_template(std::unique_ptr(func.release())) 34 | {} 35 | 36 | cpp_entity_kind do_get_entity_kind() const noexcept override; 37 | 38 | friend basic_builder; 39 | }; 40 | 41 | /// A [cppast::cpp_entity]() modelling a class template specialization. 42 | class cpp_class_template_specialization final : public cpp_template_specialization 43 | { 44 | public: 45 | static cpp_entity_kind kind() noexcept; 46 | 47 | /// Builder for [cppast::cpp_class_template_specialization](). 48 | class builder : public specialization_builder 49 | { 50 | public: 51 | using specialization_builder::specialization_builder; 52 | }; 53 | 54 | /// A reference to the class that is being specialized. 55 | const cpp_class& class_() const noexcept 56 | { 57 | return static_cast(*begin()); 58 | } 59 | 60 | private: 61 | cpp_class_template_specialization(std::unique_ptr func, cpp_template_ref primary) 62 | : cpp_template_specialization(std::unique_ptr(func.release()), primary) 63 | {} 64 | 65 | cpp_entity_kind do_get_entity_kind() const noexcept override; 66 | 67 | friend specialization_builder; 68 | }; 69 | } // namespace cppast 70 | 71 | #endif // CPPAST_CPP_CLASS_TEMPLATE_HPP_INCLUDED 72 | -------------------------------------------------------------------------------- /include/cppast/cpp_concept.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_CONCEPT_HPP_INCLUDED 5 | #define CPPAST_CPP_CONCEPT_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace cppast 12 | { 13 | /// A [[cppast::cpp_entity]() modelling a c++ concept declaration 14 | /// \notes while concepts are technically templates, 15 | /// this is not a [cppast::cpp_template](), 16 | /// as concepts act very differently from other templates 17 | class cpp_concept final : public cpp_entity 18 | { 19 | public: 20 | static cpp_entity_kind kind() noexcept; 21 | 22 | /// \returns the template parameters as a string 23 | const cpp_token_string& parameters() const noexcept 24 | { 25 | return parameters_; 26 | } 27 | 28 | /// \returns the [cppast::cpp_expression]() defining the concept constraint 29 | const cpp_expression& constraint_expression() const noexcept 30 | { 31 | return *expression_; 32 | } 33 | 34 | class builder 35 | { 36 | public: 37 | builder(std::string name) : concept_(new cpp_concept(std::move(name))) {} 38 | 39 | cpp_token_string& set_parameters(cpp_token_string string) noexcept 40 | { 41 | concept_->parameters_ = std::move(string); 42 | return concept_->parameters_; 43 | } 44 | 45 | cpp_expression& set_expression(std::unique_ptr expression) noexcept 46 | { 47 | concept_->expression_ = std::move(expression); 48 | return *concept_->expression_; 49 | } 50 | 51 | std::unique_ptr finish(const cpp_entity_index& idx, cpp_entity_id id); 52 | 53 | private: 54 | std::unique_ptr concept_; 55 | }; 56 | 57 | private: 58 | cpp_concept(std::string name) : cpp_entity(std::move(name)), parameters_({}) {} 59 | 60 | cpp_entity_kind do_get_entity_kind() const noexcept override; 61 | 62 | cpp_token_string parameters_; 63 | 64 | std::unique_ptr expression_; 65 | }; 66 | 67 | } // namespace cppast 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/cppast/cpp_decltype_type.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_DECLTYPE_TYPE_HPP_INCLUDED 5 | #define CPPAST_CPP_DECLTYPE_TYPE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_type]() that isn't given but taken from an expression. 13 | class cpp_decltype_type final : public cpp_type 14 | { 15 | public: 16 | /// \returns A newly created `decltype` type. 17 | static std::unique_ptr build(std::unique_ptr expr) 18 | { 19 | return std::unique_ptr(new cpp_decltype_type(std::move(expr))); 20 | } 21 | 22 | /// \returns A reference to the expression given. 23 | const cpp_expression& expression() const noexcept 24 | { 25 | return *expr_; 26 | } 27 | 28 | private: 29 | cpp_decltype_type(std::unique_ptr expr) : expr_(std::move(expr)) {} 30 | 31 | cpp_type_kind do_get_kind() const noexcept override 32 | { 33 | return cpp_type_kind::decltype_t; 34 | } 35 | 36 | std::unique_ptr expr_; 37 | }; 38 | 39 | /// A [cppast::cpp_type]() that isn't given but deduced using the `decltype` rules. 40 | class cpp_decltype_auto_type final : public cpp_type 41 | { 42 | public: 43 | /// \returns A newly created `auto` type. 44 | static std::unique_ptr build() 45 | { 46 | return std::unique_ptr(new cpp_decltype_auto_type); 47 | } 48 | 49 | private: 50 | cpp_decltype_auto_type() = default; 51 | 52 | cpp_type_kind do_get_kind() const noexcept override 53 | { 54 | return cpp_type_kind::decltype_auto_t; 55 | } 56 | }; 57 | } // namespace cppast 58 | 59 | #endif // CPPAST_CPP_DECLTYPE_TYPE_HPP_INCLUDED 60 | -------------------------------------------------------------------------------- /include/cppast/cpp_entity_container.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ENTITY_CONTAINER_HPP_INCLUDED 5 | #define CPPAST_CPP_ENTITY_CONTAINER_HPP_INCLUDED 6 | 7 | #include 8 | 9 | namespace cppast 10 | { 11 | /// Helper class for entities that are containers. 12 | /// 13 | /// Inherit from it to generate container access. 14 | template 15 | class cpp_entity_container 16 | { 17 | public: 18 | using iterator = typename detail::intrusive_list::const_iterator; 19 | 20 | /// \returns A const iterator to the first child. 21 | iterator begin() const noexcept 22 | { 23 | return children_.begin(); 24 | } 25 | 26 | /// \returns A const iterator to the last child. 27 | iterator end() const noexcept 28 | { 29 | return children_.end(); 30 | } 31 | 32 | protected: 33 | /// \effects Adds a new child to the container. 34 | void add_child(std::unique_ptr ptr) noexcept 35 | { 36 | children_.push_back(static_cast(*this), std::move(ptr)); 37 | } 38 | 39 | /// \returns A non-const iterator to the first child. 40 | typename detail::intrusive_list::iterator mutable_begin() noexcept 41 | { 42 | return children_.begin(); 43 | } 44 | 45 | /// \returns A non-const iterator one past the last child. 46 | typename detail::intrusive_list::iterator mutable_end() noexcept 47 | { 48 | return children_.begin(); 49 | } 50 | 51 | ~cpp_entity_container() noexcept = default; 52 | 53 | private: 54 | detail::intrusive_list children_; 55 | }; 56 | } // namespace cppast 57 | 58 | #endif // CPPAST_CPP_ENTITY_CONTAINER_HPP_INCLUDED 59 | -------------------------------------------------------------------------------- /include/cppast/cpp_entity_kind.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ENTITY_KIND_HPP_INCLUDED 5 | #define CPPAST_CPP_ENTITY_KIND_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// All possible kinds of C++ entities. 13 | enum class cpp_entity_kind 14 | { 15 | file_t, 16 | 17 | macro_parameter_t, 18 | macro_definition_t, 19 | include_directive_t, 20 | 21 | language_linkage_t, 22 | 23 | namespace_t, 24 | namespace_alias_t, 25 | using_directive_t, 26 | using_declaration_t, 27 | 28 | type_alias_t, 29 | 30 | enum_t, 31 | enum_value_t, 32 | 33 | class_t, 34 | access_specifier_t, 35 | base_class_t, 36 | 37 | variable_t, 38 | member_variable_t, 39 | bitfield_t, 40 | 41 | function_parameter_t, 42 | function_t, 43 | member_function_t, 44 | conversion_op_t, 45 | constructor_t, 46 | destructor_t, 47 | 48 | friend_t, 49 | 50 | template_type_parameter_t, 51 | non_type_template_parameter_t, 52 | template_template_parameter_t, 53 | 54 | alias_template_t, 55 | variable_template_t, 56 | function_template_t, 57 | function_template_specialization_t, 58 | class_template_t, 59 | class_template_specialization_t, 60 | concept_t, 61 | 62 | static_assert_t, 63 | 64 | unexposed_t, 65 | 66 | count, 67 | }; 68 | 69 | /// \returns A human readable string describing the entity kind. 70 | const char* to_string(cpp_entity_kind kind) noexcept; 71 | 72 | /// \returns Whether or not a given entity kind is a C++ function, 73 | /// that is, it dervies from [cppast::cpp_function_base](). 74 | bool is_function(cpp_entity_kind kind) noexcept; 75 | 76 | /// \returns Whether or not a given entity kind is a C++ (template) parameter. 77 | bool is_parameter(cpp_entity_kind kind) noexcept; 78 | 79 | /// \returns Whether or not a given entity kind is a C++ template, 80 | /// that is, it dervies from [cppast::cpp_template](). 81 | /// \notes A template template parameter is not considered a template for this function. 82 | /// \notes Template specializations are also considered templates here. 83 | bool is_template(cpp_entity_kind kind) noexcept; 84 | 85 | /// \returns Whether or not a given entity kind is a specialization of a C++ template, 86 | /// that is, it derives from [cppast::cpp_template_specialization](). 87 | bool is_template_specialization(cpp_entity_kind kind) noexcept; 88 | } // namespace cppast 89 | 90 | #endif // CPPAST_CPP_ENTITY_KIND_HPP_INCLUDED 91 | -------------------------------------------------------------------------------- /include/cppast/cpp_entity_ref.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ENTITY_REF_HPP_INCLUDED 5 | #define CPPAST_CPP_ENTITY_REF_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace cppast 15 | { 16 | 17 | /// A basic reference to some kind of [cppast::cpp_entity](). 18 | /// 19 | /// It can either refer to a single [cppast::cpp_entity]() 20 | /// or multiple. 21 | /// In the later case it is *overloaded*. 22 | template 23 | class basic_cpp_entity_ref 24 | { 25 | public: 26 | /// \effects Creates it giving it the target id and name. 27 | basic_cpp_entity_ref(cpp_entity_id target_id, std::string target_name) 28 | : target_(std::move(target_id)), name_(std::move(target_name)) 29 | {} 30 | 31 | /// \effects Creates it giving it multiple target ids and name. 32 | /// \notes This is to refer to an overloaded function. 33 | basic_cpp_entity_ref(std::vector target_ids, std::string target_name) 34 | : target_(std::move(target_ids)), name_(std::move(target_name)) 35 | {} 36 | 37 | /// \returns The name of the reference, as spelled in the source code. 38 | const std::string& name() const noexcept 39 | { 40 | return name_; 41 | } 42 | 43 | /// \returns Whether or not it refers to multiple entities. 44 | bool is_overloaded() const noexcept 45 | { 46 | return target_.has_value(type_safe::variant_type>{}); 47 | } 48 | 49 | /// \returns The number of entities it refers to. 50 | type_safe::size_t no_overloaded() const noexcept 51 | { 52 | return id().size(); 53 | } 54 | 55 | /// \returns An array reference to the id or ids it refers to. 56 | type_safe::array_ref id() const noexcept 57 | { 58 | if (is_overloaded()) 59 | { 60 | auto& vec = target_.value(type_safe::variant_type>{}); 61 | return type_safe::ref(vec.data(), vec.size()); 62 | } 63 | else 64 | { 65 | auto& id = target_.value(type_safe::variant_type{}); 66 | return type_safe::ref(&id, 1u); 67 | } 68 | } 69 | 70 | /// \returns An array reference to the entities it refers to. 71 | /// The return type provides `operator[]` + `size()`, 72 | /// as well as `begin()` and `end()` returning forward iterators. 73 | /// \exclude return 74 | std::vector> get(const cpp_entity_index& idx) const 75 | { 76 | std::vector> result; 77 | get_impl(std::is_convertible{}, result, idx); 78 | return result; 79 | } 80 | 81 | private: 82 | void get_impl(std::true_type, std::vector>& result, 83 | const cpp_entity_index& idx) const 84 | { 85 | for (auto& cur : id()) 86 | for (auto& ns : idx.lookup_namespace(cur)) 87 | result.push_back(ns); 88 | if (!std::is_same::value) 89 | get_impl(std::false_type{}, result, idx); 90 | } 91 | 92 | void get_impl(std::false_type, std::vector>& result, 93 | const cpp_entity_index& idx) const 94 | { 95 | for (auto& cur : id()) 96 | { 97 | auto entity = idx.lookup(cur).map([](const cpp_entity& e) { 98 | DEBUG_ASSERT(Predicate{}(e), detail::precondition_error_handler{}, 99 | "invalid entity type"); 100 | return type_safe::ref(static_cast(e)); 101 | }); 102 | if (entity) 103 | result.push_back(type_safe::ref(entity.value())); 104 | } 105 | } 106 | 107 | type_safe::variant> target_; 108 | std::string name_; 109 | }; 110 | 111 | /// \exclude 112 | namespace detail 113 | { 114 | struct cpp_entity_ref_predicate 115 | { 116 | bool operator()(const cpp_entity&) 117 | { 118 | return true; 119 | } 120 | }; 121 | } // namespace detail 122 | 123 | /// A [cppast::basic_cpp_entity_ref]() to any [cppast::cpp_entity](). 124 | using cpp_entity_ref = basic_cpp_entity_ref; 125 | } // namespace cppast 126 | 127 | #endif // CPPAST_CPP_ENTITY_REF_HPP_INCLUDED 128 | -------------------------------------------------------------------------------- /include/cppast/cpp_enum.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_ENUM_HPP_INCLUDED 5 | #define CPPAST_CPP_ENUM_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace cppast 19 | { 20 | /// A [cppast::cpp_entity]() modelling the value of an [cppast::cpp_enum](). 21 | class cpp_enum_value final : public cpp_entity 22 | { 23 | public: 24 | static cpp_entity_kind kind() noexcept; 25 | 26 | /// \returns A newly created and registered enum value. 27 | /// \notes `value` may be `nullptr`, in which case the enum has an implicit value. 28 | static std::unique_ptr build(const cpp_entity_index& idx, cpp_entity_id id, 29 | std::string name, 30 | std::unique_ptr value = nullptr); 31 | 32 | /// \returns A [ts::optional_ref]() to the [cppast::cpp_expression]() that is the enum value. 33 | /// \notes It only has an associated expression if the value is explictly given. 34 | type_safe::optional_ref value() const noexcept 35 | { 36 | return type_safe::opt_cref(value_.get()); 37 | } 38 | 39 | private: 40 | cpp_enum_value(std::string name, std::unique_ptr value) 41 | : cpp_entity(std::move(name)), value_(std::move(value)) 42 | {} 43 | 44 | cpp_entity_kind do_get_entity_kind() const noexcept override; 45 | 46 | std::unique_ptr value_; 47 | }; 48 | 49 | /// A [cppast::cpp_entity]() modelling a C++ enumeration. 50 | /// 51 | /// This can either be a definition or just a forward declaration. 52 | /// If it is just forward declared, it will not have any children. 53 | class cpp_enum final : public cpp_entity, 54 | public cpp_entity_container, 55 | public cpp_forward_declarable 56 | { 57 | public: 58 | static cpp_entity_kind kind() noexcept; 59 | 60 | /// Builds a [cppast::cpp_enum](). 61 | class builder 62 | { 63 | public: 64 | /// \effects Sets the name, underlying type and whether it is scoped. 65 | builder(std::string name, bool scoped, std::unique_ptr type, bool explicit_type) 66 | : enum_(new cpp_enum(std::move(name), std::move(type), explicit_type, scoped)) 67 | {} 68 | 69 | /// \effects Adds a [cppast::cpp_enum_value](). 70 | void add_value(std::unique_ptr value) 71 | { 72 | enum_->add_child(std::move(value)); 73 | } 74 | 75 | /// \returns The not yet finished enumeration. 76 | cpp_enum& get() noexcept 77 | { 78 | return *enum_; 79 | } 80 | 81 | /// \effects Registers the enum in the [cppast::cpp_entity_index](), 82 | /// using the given [cppast::cpp_entity_id](). 83 | /// \returns The finished enum. 84 | std::unique_ptr finish( 85 | const cpp_entity_index& idx, cpp_entity_id id, 86 | type_safe::optional semantic_parent) noexcept 87 | { 88 | enum_->set_semantic_parent(std::move(semantic_parent)); 89 | idx.register_definition(std::move(id), type_safe::ref(*enum_)); 90 | return std::move(enum_); 91 | } 92 | 93 | /// \effects Marks the enum as forward declaration. 94 | /// \returns The finished enum. 95 | std::unique_ptr finish_declaration(const cpp_entity_index& idx, 96 | cpp_entity_id definition_id) noexcept 97 | { 98 | enum_->mark_declaration(definition_id); 99 | idx.register_forward_declaration(std::move(definition_id), type_safe::ref(*enum_)); 100 | return std::move(enum_); 101 | } 102 | 103 | private: 104 | std::unique_ptr enum_; 105 | }; 106 | 107 | /// \returns A reference to the underlying [cppast::cpp_type]() of the enum. 108 | const cpp_type& underlying_type() const noexcept 109 | { 110 | return *type_; 111 | } 112 | 113 | /// \returns Whether or not the underlying type is explictly given. 114 | bool has_explicit_type() const noexcept 115 | { 116 | return type_given_; 117 | } 118 | 119 | /// \returns Whether or not it is a scoped enumeration (i.e. an `enum class`). 120 | bool is_scoped() const noexcept 121 | { 122 | return scoped_; 123 | } 124 | 125 | private: 126 | cpp_enum(std::string name, std::unique_ptr type, bool type_given, bool scoped) 127 | : cpp_entity(std::move(name)), type_(std::move(type)), scoped_(scoped), type_given_(type_given) 128 | {} 129 | 130 | cpp_entity_kind do_get_entity_kind() const noexcept override; 131 | 132 | type_safe::optional do_get_scope_name() const override; 133 | 134 | std::unique_ptr type_; 135 | bool scoped_, type_given_; 136 | }; 137 | } // namespace cppast 138 | 139 | #endif // CPPAST_CPP_ENUM_HPP_INCLUDED 140 | -------------------------------------------------------------------------------- /include/cppast/cpp_expression.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_EXPRESSION_HPP_INCLUDED 5 | #define CPPAST_CPP_EXPRESSION_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace cppast 14 | { 15 | /// The kind of a [cppast::cpp_expression](). 16 | enum class cpp_expression_kind 17 | { 18 | literal_t, 19 | 20 | unexposed_t, 21 | }; 22 | 23 | /// Base class for all C++ expressions. 24 | class cpp_expression 25 | { 26 | public: 27 | cpp_expression(const cpp_expression&) = delete; 28 | cpp_expression& operator=(const cpp_expression&) = delete; 29 | 30 | virtual ~cpp_expression() noexcept = default; 31 | 32 | /// \returns The [cppast::cpp_expression_kind](). 33 | cpp_expression_kind kind() const noexcept 34 | { 35 | return do_get_kind(); 36 | } 37 | 38 | /// \returns The type of the expression. 39 | const cpp_type& type() const noexcept 40 | { 41 | return *type_; 42 | } 43 | 44 | /// \returns The specified user data. 45 | void* user_data() const noexcept 46 | { 47 | return user_data_.load(); 48 | } 49 | 50 | /// \effects Sets some kind of user data. 51 | /// 52 | /// User data is just some kind of pointer, there are no requirements. 53 | /// The class will do no lifetime management. 54 | /// 55 | /// User data is useful if you need to store additional data for an entity without the need to 56 | /// maintain a registry. 57 | void set_user_data(void* data) const noexcept 58 | { 59 | user_data_ = data; 60 | } 61 | 62 | protected: 63 | /// \effects Creates it given the type. 64 | /// \requires The type must not be `nullptr`. 65 | cpp_expression(std::unique_ptr type) : type_(std::move(type)), user_data_(nullptr) 66 | { 67 | DEBUG_ASSERT(type_ != nullptr, detail::precondition_error_handler{}); 68 | } 69 | 70 | private: 71 | /// \returns The [cppast::cpp_expression_kind](). 72 | virtual cpp_expression_kind do_get_kind() const noexcept = 0; 73 | 74 | std::unique_ptr type_; 75 | mutable std::atomic user_data_; 76 | }; 77 | 78 | /// An unexposed [cppast::cpp_expression](). 79 | /// 80 | /// There is no further information than a string available. 81 | class cpp_unexposed_expression final : public cpp_expression 82 | { 83 | public: 84 | /// \returns A newly created unexposed expression. 85 | static std::unique_ptr build(std::unique_ptr type, 86 | cpp_token_string str) 87 | { 88 | return std::unique_ptr( 89 | new cpp_unexposed_expression(std::move(type), std::move(str))); 90 | } 91 | 92 | /// \returns The expression as a string. 93 | const cpp_token_string& expression() const noexcept 94 | { 95 | return str_; 96 | } 97 | 98 | private: 99 | cpp_unexposed_expression(std::unique_ptr type, cpp_token_string str) 100 | : cpp_expression(std::move(type)), str_(std::move(str)) 101 | {} 102 | 103 | cpp_expression_kind do_get_kind() const noexcept override 104 | { 105 | return cpp_expression_kind::unexposed_t; 106 | } 107 | 108 | cpp_token_string str_; 109 | }; 110 | 111 | /// A [cppast::cpp_expression]() that is a literal. 112 | class cpp_literal_expression final : public cpp_expression 113 | { 114 | public: 115 | /// \returns A newly created literal expression. 116 | static std::unique_ptr build(std::unique_ptr type, 117 | std::string value) 118 | { 119 | return std::unique_ptr( 120 | new cpp_literal_expression(std::move(type), std::move(value))); 121 | } 122 | 123 | /// \returns The value of the literal, as string. 124 | const std::string& value() const noexcept 125 | { 126 | return value_; 127 | } 128 | 129 | private: 130 | cpp_literal_expression(std::unique_ptr type, std::string value) 131 | : cpp_expression(std::move(type)), value_(std::move(value)) 132 | {} 133 | 134 | cpp_expression_kind do_get_kind() const noexcept override 135 | { 136 | return cpp_expression_kind::literal_t; 137 | } 138 | 139 | std::string value_; 140 | }; 141 | 142 | /// \exclude 143 | namespace detail 144 | { 145 | void write_expression(code_generator::output& output, const cpp_expression& expr); 146 | } // namespace detail 147 | } // namespace cppast 148 | 149 | #endif // CPPAST_CPP_EXPRESSION_HPP_INCLUDED 150 | -------------------------------------------------------------------------------- /include/cppast/cpp_file.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_FILE_HPP_INCLUDED 5 | #define CPPAST_CPP_FILE_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cppast 14 | { 15 | /// An unmatched documentation comment. 16 | struct cpp_doc_comment 17 | { 18 | std::string content; 19 | unsigned line; 20 | 21 | cpp_doc_comment(std::string content, unsigned line) : content(std::move(content)), line(line) {} 22 | }; 23 | 24 | /// A [cppast::cpp_entity]() modelling a file. 25 | /// 26 | /// This is the top-level entity of the AST. 27 | class cpp_file final : public cpp_entity, public cpp_entity_container 28 | { 29 | public: 30 | static cpp_entity_kind kind() noexcept; 31 | 32 | /// Builds a [cppast::cpp_file](). 33 | class builder 34 | { 35 | public: 36 | /// \effects Sets the file name. 37 | explicit builder(std::string name) : file_(new cpp_file(std::move(name))) {} 38 | 39 | /// \effects Adds an entity. 40 | void add_child(std::unique_ptr child) noexcept 41 | { 42 | file_->add_child(std::move(child)); 43 | } 44 | 45 | /// \effects Adds an unmatched documentation comment. 46 | void add_unmatched_comment(cpp_doc_comment comment) 47 | { 48 | file_->comments_.push_back(std::move(comment)); 49 | } 50 | 51 | /// \returns The not yet finished file. 52 | cpp_file& get() noexcept 53 | { 54 | return *file_; 55 | } 56 | 57 | /// \effects Registers the file in the [cppast::cpp_entity_index](). 58 | /// It will use the file name as identifier. 59 | /// \returns The finished file, or `nullptr`, if that file was already registered. 60 | std::unique_ptr finish(const cpp_entity_index& idx) noexcept 61 | { 62 | auto res = idx.register_file(cpp_entity_id(file_->name()), type_safe::ref(*file_)); 63 | return res ? std::move(file_) : nullptr; 64 | } 65 | 66 | private: 67 | std::unique_ptr file_; 68 | }; 69 | 70 | /// \returns The unmatched documentation comments. 71 | type_safe::array_ref unmatched_comments() const noexcept 72 | { 73 | return type_safe::ref(comments_.data(), comments_.size()); 74 | } 75 | 76 | private: 77 | cpp_file(std::string name) : cpp_entity(std::move(name)) {} 78 | 79 | /// \returns [cpp_entity_type::file_t](). 80 | cpp_entity_kind do_get_entity_kind() const noexcept override; 81 | 82 | std::vector comments_; 83 | }; 84 | 85 | /// \exclude 86 | namespace detail 87 | { 88 | struct cpp_file_ref_predicate 89 | { 90 | bool operator()(const cpp_entity& e); 91 | }; 92 | } // namespace detail 93 | 94 | /// A reference to a [cppast::cpp_file](). 95 | using cpp_file_ref = basic_cpp_entity_ref; 96 | } // namespace cppast 97 | 98 | #endif // CPPAST_CPP_FILE_HPP_INCLUDED 99 | -------------------------------------------------------------------------------- /include/cppast/cpp_forward_declarable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_FORWARD_DECLARABLE_HPP_INCLUDED 5 | #define CPPAST_CPP_FORWARD_DECLARABLE_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace cppast 15 | { 16 | /// Mixin base class for all entities that can have a forward declaration. 17 | /// 18 | /// Examples are [cppast::cpp_enum]() or [cppast::cpp_class](), 19 | /// but also [cppast::cpp_function_base](). 20 | /// Those entities can have multiple declarations and one definition. 21 | class cpp_forward_declarable 22 | { 23 | public: 24 | /// \returns Whether or not the entity is the definition. 25 | bool is_definition() const noexcept 26 | { 27 | return !definition_.has_value(); 28 | } 29 | 30 | /// \returns Whether or not the entity is "just" a declaration. 31 | bool is_declaration() const noexcept 32 | { 33 | return definition_.has_value(); 34 | } 35 | 36 | /// \returns The [cppast::cpp_entity_id]() of the definition, 37 | /// if the current entity is not the definition. 38 | const type_safe::optional& definition() const noexcept 39 | { 40 | return definition_; 41 | } 42 | 43 | /// \returns A reference to the semantic parent of the entity. 44 | /// This applies only to out-of-line definitions 45 | /// and is the entity which owns the declaration. 46 | const type_safe::optional& semantic_parent() const noexcept 47 | { 48 | return semantic_parent_; 49 | } 50 | 51 | /// \returns The name of the semantic parent, if it has one, 52 | /// else the empty string. 53 | /// \notes This may include template parameters. 54 | std::string semantic_scope() const noexcept 55 | { 56 | return type_safe::copy(semantic_parent_.map(&cpp_entity_ref::name)).value_or(""); 57 | } 58 | 59 | protected: 60 | /// \effects Marks the entity as definition. 61 | /// \notes If it is not a definition, 62 | /// [*set_definition]() must be called. 63 | cpp_forward_declarable() noexcept = default; 64 | 65 | ~cpp_forward_declarable() noexcept = default; 66 | 67 | /// \effects Sets the definition entity, 68 | /// marking it as a forward declaration. 69 | void mark_declaration(cpp_entity_id def) noexcept 70 | { 71 | definition_ = std::move(def); 72 | } 73 | 74 | /// \effects Sets the semantic parent of the entity. 75 | void set_semantic_parent(type_safe::optional semantic_parent) noexcept 76 | { 77 | semantic_parent_ = std::move(semantic_parent); 78 | } 79 | 80 | private: 81 | type_safe::optional semantic_parent_; 82 | type_safe::optional definition_; 83 | }; 84 | 85 | /// \returns Whether or not the given entity is a definition. 86 | bool is_definition(const cpp_entity& e) noexcept; 87 | 88 | /// Gets the definition of an entity. 89 | /// \returns A [ts::optional_ref]() to the entity that is the definition. 90 | /// If the entity is a definition or not derived from [cppast::cpp_forward_declarable]() (only valid 91 | /// for the generic entity overload), returns a reference to the entity itself. Otherwise lookups 92 | /// the definition id and returns it. \notes The return value will only be `nullptr`, if the 93 | /// definition is not registered. \group get_definition 94 | type_safe::optional_ref get_definition(const cpp_entity_index& idx, 95 | const cpp_entity& e); 96 | /// \group get_definition 97 | type_safe::optional_ref get_definition(const cpp_entity_index& idx, 98 | const cpp_enum& e); 99 | /// \group get_definition 100 | type_safe::optional_ref get_definition(const cpp_entity_index& idx, 101 | const cpp_class& e); 102 | /// \group get_definition 103 | type_safe::optional_ref get_definition(const cpp_entity_index& idx, 104 | const cpp_variable& e); 105 | /// \group get_definition 106 | type_safe::optional_ref get_definition(const cpp_entity_index& idx, 107 | const cpp_function_base& e); 108 | 109 | } // namespace cppast 110 | 111 | #endif // CPPAST_CPP_FORWARD_DECLARABLE_HPP_INCLUDED 112 | -------------------------------------------------------------------------------- /include/cppast/cpp_friend.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_FRIEND_HPP_INCLUDED 5 | #define CPPAST_CPP_FRIEND_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cppast 14 | { 15 | /// A [cppast::cpp_entity]() representing a friend declaration. 16 | /// 17 | /// It can either declare or define a `friend` function (template), declare a `friend` class, 18 | /// or refer to an existing type. 19 | class cpp_friend : public cpp_entity, private cpp_entity_container 20 | { 21 | public: 22 | static cpp_entity_kind kind() noexcept; 23 | 24 | /// \returns A newly created friend declaring the given entity as `friend`. 25 | /// \notes The friend declaration itself will not be registered, 26 | /// but the referring entity is. 27 | static std::unique_ptr build(std::unique_ptr e) 28 | { 29 | return std::unique_ptr(new cpp_friend(std::move(e))); 30 | } 31 | 32 | /// \returns A newly created friend declaring the given type as `friend`. 33 | /// \notes It will not be registered. 34 | static std::unique_ptr build(std::unique_ptr type) 35 | { 36 | return std::unique_ptr(new cpp_friend(std::move(type))); 37 | } 38 | 39 | /// \returns An optional reference to the entity it declares as friend, or `nullptr`. 40 | type_safe::optional_ref entity() const noexcept 41 | { 42 | if (begin() == end()) 43 | return nullptr; 44 | return type_safe::ref(*begin()); 45 | } 46 | 47 | /// \returns An optional reference to the type it declares as friend, or `nullptr`. 48 | type_safe::optional_ref type() const noexcept 49 | { 50 | return type_safe::opt_ref(type_.get()); 51 | } 52 | 53 | private: 54 | cpp_friend(std::unique_ptr e) : cpp_entity("") 55 | { 56 | add_child(std::move(e)); 57 | } 58 | 59 | cpp_friend(std::unique_ptr type) : cpp_entity(""), type_(std::move(type)) {} 60 | 61 | cpp_entity_kind do_get_entity_kind() const noexcept override; 62 | 63 | std::unique_ptr type_; 64 | 65 | friend cpp_entity_container; 66 | }; 67 | } // namespace cppast 68 | 69 | #endif // CPPAST_CPP_FRIEND_HPP_INCLUDED 70 | -------------------------------------------------------------------------------- /include/cppast/cpp_function_template.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_FUNCTION_TEMPLATE_HPP_INCLUDED 5 | #define CPPAST_CPP_FUNCTION_TEMPLATE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_entity]() modelling a function template. 13 | class cpp_function_template final : public cpp_template 14 | { 15 | public: 16 | static cpp_entity_kind kind() noexcept; 17 | 18 | /// Builder for [cppast::cpp_function_template](). 19 | class builder : public basic_builder 20 | { 21 | public: 22 | using basic_builder::basic_builder; 23 | }; 24 | 25 | /// A reference to the function that is being templated. 26 | const cpp_function_base& function() const noexcept 27 | { 28 | return static_cast(*begin()); 29 | } 30 | 31 | private: 32 | cpp_function_template(std::unique_ptr func) 33 | : cpp_template(std::unique_ptr(func.release())) 34 | {} 35 | 36 | cpp_entity_kind do_get_entity_kind() const noexcept override; 37 | 38 | friend basic_builder; 39 | }; 40 | 41 | /// A [cppast::cpp_entity]() modelling a function template specialization. 42 | class cpp_function_template_specialization final : public cpp_template_specialization 43 | { 44 | public: 45 | static cpp_entity_kind kind() noexcept; 46 | 47 | /// Builder for [cppast::cpp_function_template_specialization](). 48 | class builder 49 | : public specialization_builder 50 | { 51 | public: 52 | using specialization_builder::specialization_builder; 53 | 54 | private: 55 | using specialization_builder::add_parameter; 56 | }; 57 | 58 | /// A reference to the function that is being specialized. 59 | const cpp_function_base& function() const noexcept 60 | { 61 | return static_cast(*begin()); 62 | } 63 | 64 | private: 65 | cpp_function_template_specialization(std::unique_ptr func, 66 | cpp_template_ref primary) 67 | : cpp_template_specialization(std::unique_ptr(func.release()), primary) 68 | {} 69 | 70 | cpp_entity_kind do_get_entity_kind() const noexcept override; 71 | 72 | friend specialization_builder; 73 | }; 74 | } // namespace cppast 75 | 76 | #endif // CPPAST_CPP_FUNCTION_TEMPLATE_HPP_INCLUDED 77 | -------------------------------------------------------------------------------- /include/cppast/cpp_language_linkage.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_LANGUAGE_LINKAGE_HPP_INCLUDED 5 | #define CPPAST_CPP_LANGUAGE_LINKAGE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_entity]() modelling a language linkage. 13 | class cpp_language_linkage final : public cpp_entity, 14 | public cpp_entity_container 15 | { 16 | public: 17 | static cpp_entity_kind kind() noexcept; 18 | 19 | /// Builds a [cppast::cpp_language_linkage](). 20 | class builder 21 | { 22 | public: 23 | /// \effects Sets the name, that is the kind of language linkage. 24 | explicit builder(std::string name) : linkage_(new cpp_language_linkage(std::move(name))) {} 25 | 26 | /// \effects Adds an entity to the language linkage. 27 | void add_child(std::unique_ptr child) 28 | { 29 | linkage_->add_child(std::move(child)); 30 | } 31 | 32 | /// \returns The not yet finished language linkage. 33 | cpp_language_linkage& get() const noexcept 34 | { 35 | return *linkage_; 36 | } 37 | 38 | /// \returns The finalized language linkage. 39 | /// \notes It is not registered on purpose as nothing can refer to it. 40 | std::unique_ptr finish() 41 | { 42 | return std::move(linkage_); 43 | } 44 | 45 | private: 46 | std::unique_ptr linkage_; 47 | }; 48 | 49 | /// \returns `true` if the linkage is a block, `false` otherwise. 50 | bool is_block() const noexcept; 51 | 52 | private: 53 | using cpp_entity::cpp_entity; 54 | 55 | cpp_entity_kind do_get_entity_kind() const noexcept override; 56 | }; 57 | } // namespace cppast 58 | 59 | #endif // CPPAST_CPP_LANGUAGE_LINKAGE_HPP_INCLUDED 60 | -------------------------------------------------------------------------------- /include/cppast/cpp_member_variable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_MEMBER_VARIABLE_HPP_INCLUDED 5 | #define CPPAST_CPP_MEMBER_VARIABLE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// Base class for all kinds of member variables. 13 | class cpp_member_variable_base : public cpp_entity, public cpp_variable_base 14 | { 15 | public: 16 | /// \returns Whether or not the member variable is declared `mutable`. 17 | bool is_mutable() const noexcept 18 | { 19 | return mutable_; 20 | } 21 | 22 | cpp_member_variable_base(std::string name, std::unique_ptr type, 23 | std::unique_ptr def, bool is_mutable) 24 | : cpp_entity(std::move(name)), cpp_variable_base(std::move(type), std::move(def)), 25 | mutable_(is_mutable) 26 | {} 27 | 28 | private: 29 | bool mutable_; 30 | }; 31 | 32 | /// A [cppast::cpp_entity]() modelling a C++ member variable. 33 | class cpp_member_variable final : public cpp_member_variable_base 34 | { 35 | public: 36 | static cpp_entity_kind kind() noexcept; 37 | 38 | /// \returns A newly created and registered member variable. 39 | /// \notes `def` may be `nullptr` in which case there is no member initializer provided. 40 | static std::unique_ptr build(const cpp_entity_index& idx, cpp_entity_id id, 41 | std::string name, 42 | std::unique_ptr type, 43 | std::unique_ptr def, 44 | bool is_mutable); 45 | 46 | private: 47 | using cpp_member_variable_base::cpp_member_variable_base; 48 | 49 | cpp_entity_kind do_get_entity_kind() const noexcept override; 50 | }; 51 | 52 | /// A [cppast::cpp_entity]() modelling a C++ bitfield. 53 | class cpp_bitfield final : public cpp_member_variable_base 54 | { 55 | public: 56 | static cpp_entity_kind kind() noexcept; 57 | 58 | /// \returns A newly created and registered bitfield. 59 | /// \notes It cannot have a member initializer, i.e. default value. 60 | static std::unique_ptr build(const cpp_entity_index& idx, cpp_entity_id id, 61 | std::string name, std::unique_ptr type, 62 | unsigned no_bits, bool is_mutable); 63 | 64 | /// \returns A newly created unnamed bitfield. 65 | /// \notes It will not be registered, as it is unnamed. 66 | static std::unique_ptr build(std::unique_ptr type, unsigned no_bits, 67 | bool is_mutable); 68 | 69 | /// \returns The number of bits of the bitfield. 70 | unsigned no_bits() const noexcept 71 | { 72 | return bits_; 73 | } 74 | 75 | private: 76 | cpp_bitfield(std::string name, std::unique_ptr type, unsigned no_bits, 77 | bool is_mutable) 78 | : cpp_member_variable_base(std::move(name), std::move(type), nullptr, is_mutable), 79 | bits_(no_bits) 80 | {} 81 | 82 | cpp_entity_kind do_get_entity_kind() const noexcept override; 83 | 84 | unsigned bits_; 85 | }; 86 | } // namespace cppast 87 | 88 | #endif // CPPAST_CPP_MEMBER_VARIABLE_HPP_INCLUDED 89 | -------------------------------------------------------------------------------- /include/cppast/cpp_static_assert.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_STATIC_ASSERT_HPP_INCLUDED 5 | #define CPPAST_CPP_STATIC_ASSERT_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | class cpp_static_assert : public cpp_entity 13 | { 14 | public: 15 | static cpp_entity_kind kind() noexcept; 16 | 17 | /// \returns A newly created `static_assert()` entity. 18 | /// \notes It will not be registered as nothing can refer to it. 19 | static std::unique_ptr build(std::unique_ptr expr, 20 | std::string msg) 21 | { 22 | return std::unique_ptr( 23 | new cpp_static_assert(std::move(expr), std::move(msg))); 24 | } 25 | 26 | /// \returns A reference to the [cppast::cpp_expression]() that is being asserted. 27 | const cpp_expression& expression() const noexcept 28 | { 29 | return *expr_; 30 | } 31 | 32 | /// \returns A reference to the message of the assertion. 33 | const std::string& message() const noexcept 34 | { 35 | return msg_; 36 | } 37 | 38 | private: 39 | cpp_static_assert(std::unique_ptr expr, std::string msg) 40 | : cpp_entity(""), expr_(std::move(expr)), msg_(std::move(msg)) 41 | {} 42 | 43 | cpp_entity_kind do_get_entity_kind() const noexcept override; 44 | 45 | std::unique_ptr expr_; 46 | std::string msg_; 47 | }; 48 | } // namespace cppast 49 | 50 | #endif // CPPAST_CPP_STATIC_ASSERT_HPP_INCLUDED 51 | -------------------------------------------------------------------------------- /include/cppast/cpp_storage_class_specifiers.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_STORAGE_CLASS_SPECIFIERS_HPP_INCLUDED 5 | #define CPPAST_CPP_STORAGE_CLASS_SPECIFIERS_HPP_INCLUDED 6 | 7 | #include 8 | 9 | namespace cppast 10 | { 11 | /// C++ storage class specifiers. 12 | /// 13 | /// See http://en.cppreference.com/w/cpp/language/storage_duration, for example. 14 | /// \notes These are just all the possible *keywords* used in a variable declaration, 15 | /// not necessarily their *semantic* meaning. 16 | enum cpp_storage_class_specifiers : int 17 | { 18 | cpp_storage_class_none = 0, //< no storage class specifier given. 19 | 20 | cpp_storage_class_auto = 1, //< *automatic* storage duration. 21 | 22 | cpp_storage_class_static = 2, //< *static* or *thread* storage duration and *internal* linkage. 23 | cpp_storage_class_extern = 4, //< *static* or *thread* storage duration and *external* linkage. 24 | 25 | cpp_storage_class_thread_local = 8, //< *thread* storage duration. 26 | /// \notes This is the only one that can be combined with the others. 27 | }; 28 | 29 | /// \returns Whether the [cppast::cpp_storage_class_specifiers]() contain `thread_local`. 30 | inline bool is_thread_local(cpp_storage_class_specifiers spec) noexcept 31 | { 32 | return (spec & cpp_storage_class_thread_local) != 0; 33 | } 34 | 35 | /// \returns Whether the [cppast::cpp_storage_class_speicifers]() contain `auto`. 36 | inline bool is_auto(cpp_storage_class_specifiers spec) noexcept 37 | { 38 | return (spec & cpp_storage_class_auto) != 0; 39 | } 40 | 41 | /// \returns Whether the [cppast::cpp_storage_class_specifiers]() contain `static`. 42 | inline bool is_static(cpp_storage_class_specifiers spec) noexcept 43 | { 44 | return (spec & cpp_storage_class_static) != 0; 45 | } 46 | 47 | /// \returns Whether the [cppast::cpp_storage_class_specifiers]() contain `extern`. 48 | inline bool is_extern(cpp_storage_class_specifiers spec) noexcept 49 | { 50 | return (spec & cpp_storage_class_extern) != 0; 51 | } 52 | } // namespace cppast 53 | 54 | #endif // CPPAST_CPP_STORAGE_CLASS_SPECIFIERS_HPP_INCLUDED 55 | -------------------------------------------------------------------------------- /include/cppast/cpp_token.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_TOKEN_HPP_INCLUDED 5 | #define CPPAST_CPP_TOKEN_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace cppast 15 | { 16 | /// The kinds of C++ tokens. 17 | enum class cpp_token_kind 18 | { 19 | identifier, //< Any identifier. 20 | keyword, //< Any keyword. 21 | int_literal, //< An integer literal. 22 | float_literal, //< A floating point literal. 23 | char_literal, //< A character literal. 24 | string_literal, //< A string literal. 25 | punctuation //< Any other punctuation. 26 | }; 27 | 28 | /// A C++ token. 29 | struct cpp_token 30 | { 31 | std::string spelling; 32 | cpp_token_kind kind; 33 | 34 | cpp_token(cpp_token_kind kind, std::string spelling) : spelling(std::move(spelling)), kind(kind) 35 | {} 36 | 37 | friend bool operator==(const cpp_token& lhs, const cpp_token& rhs) noexcept 38 | { 39 | return lhs.spelling == rhs.spelling; 40 | } 41 | 42 | friend bool operator!=(const cpp_token& lhs, const cpp_token& rhs) noexcept 43 | { 44 | return !(rhs == lhs); 45 | } 46 | }; 47 | 48 | /// A combination of multiple C++ tokens. 49 | class cpp_token_string 50 | { 51 | public: 52 | /// Builds a token string. 53 | class builder 54 | { 55 | public: 56 | builder() = default; 57 | 58 | /// \effects Adds a token. 59 | void add_token(cpp_token tok) 60 | { 61 | tokens_.push_back(std::move(tok)); 62 | } 63 | 64 | /// \effects Converts a trailing `>>` to `>` token. 65 | void unmunch(); 66 | 67 | /// \returns The finished string. 68 | cpp_token_string finish() 69 | { 70 | return cpp_token_string(std::move(tokens_)); 71 | } 72 | 73 | private: 74 | std::vector tokens_; 75 | }; 76 | 77 | /// Tokenizes a string. 78 | /// \effects Splits the string into C++ tokens. 79 | /// The string must contain valid tokens and must already be preprocessed (i.e. translation 80 | /// phase 6 is already done). \returns The tokenized string. 81 | static cpp_token_string tokenize(std::string str); 82 | 83 | /// \effects Creates it from a sequence of tokens. 84 | cpp_token_string(std::vector tokens) : tokens_(std::move(tokens)) {} 85 | 86 | /// \exclude target 87 | using iterator = std::vector::const_iterator; 88 | 89 | /// \returns An iterator to the first token. 90 | iterator begin() const noexcept 91 | { 92 | return tokens_.begin(); 93 | } 94 | 95 | /// \returns An iterator one past the last token. 96 | iterator end() const noexcept 97 | { 98 | return tokens_.end(); 99 | } 100 | 101 | /// \returns Whether or not the string is empty. 102 | bool empty() const noexcept 103 | { 104 | return tokens_.empty(); 105 | } 106 | 107 | /// \returns A reference to the first token. 108 | const cpp_token& front() const noexcept 109 | { 110 | return tokens_.front(); 111 | } 112 | 113 | /// \returns A reference to the last token. 114 | const cpp_token& back() const noexcept 115 | { 116 | return tokens_.back(); 117 | } 118 | 119 | /// \returns The string representation of the tokens, without any whitespace. 120 | std::string as_string() const; 121 | 122 | private: 123 | std::vector tokens_; 124 | 125 | friend bool operator==(const cpp_token_string& lhs, const cpp_token_string& rhs); 126 | }; 127 | 128 | bool operator==(const cpp_token_string& lhs, const cpp_token_string& rhs); 129 | 130 | inline bool operator!=(const cpp_token_string& lhs, const cpp_token_string& rhs) 131 | { 132 | return !(lhs == rhs); 133 | } 134 | } // namespace cppast 135 | 136 | #endif // CPPAST_CPP_TOKEN_HPP_INCLUDED 137 | -------------------------------------------------------------------------------- /include/cppast/cpp_type_alias.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_TYPE_ALIAS_HPP_INCLUDED 5 | #define CPPAST_CPP_TYPE_ALIAS_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_entity]() modelling a type alias/typedef. 13 | /// \notes There is no distinction between `using` and `typedef` type aliases made in the AST. 14 | class cpp_type_alias final : public cpp_entity 15 | { 16 | public: 17 | static cpp_entity_kind kind() noexcept; 18 | 19 | /// \returns A newly created and registered type alias. 20 | static std::unique_ptr build(const cpp_entity_index& idx, cpp_entity_id id, 21 | std::string name, std::unique_ptr type); 22 | 23 | /// \returns A newly created type alias that isn't registered. 24 | /// \notes This function is intendend for templated type aliases. 25 | static std::unique_ptr build(std::string name, std::unique_ptr type); 26 | 27 | /// \returns A reference to the aliased [cppast::cpp_type](). 28 | const cpp_type& underlying_type() const noexcept 29 | { 30 | return *type_; 31 | } 32 | 33 | private: 34 | cpp_type_alias(std::string name, std::unique_ptr type) 35 | : cpp_entity(std::move(name)), type_(std::move(type)) 36 | {} 37 | 38 | cpp_entity_kind do_get_entity_kind() const noexcept override; 39 | 40 | std::unique_ptr type_; 41 | }; 42 | } // namespace cppast 43 | 44 | #endif // CPPAST_CPP_TYPE_ALIAS_HPP_INCLUDED 45 | -------------------------------------------------------------------------------- /include/cppast/cpp_variable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_VARIABLE_HPP_INCLUDED 5 | #define CPPAST_CPP_VARIABLE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace cppast 13 | { 14 | /// A [cppast::cpp_entity]() modelling a C++ variable. 15 | /// \notes This is not a member variable, 16 | /// use [cppast::cpp_member_variable]() for that. 17 | /// But it can be `static` member variable. 18 | class cpp_variable final : public cpp_entity, 19 | public cpp_variable_base, 20 | public cpp_forward_declarable 21 | { 22 | public: 23 | static cpp_entity_kind kind() noexcept; 24 | 25 | /// \returns A newly created and registered variable. 26 | /// \notes The default value may be `nullptr` indicating no default value. 27 | static std::unique_ptr build(const cpp_entity_index& idx, cpp_entity_id id, 28 | std::string name, std::unique_ptr type, 29 | std::unique_ptr def, 30 | cpp_storage_class_specifiers spec, bool is_constexpr, 31 | type_safe::optional semantic_parent 32 | = {}); 33 | 34 | /// \returns A newly created variable that is a declaration. 35 | /// A declaration will not be registered and it does not have the default value. 36 | static std::unique_ptr build_declaration( 37 | cpp_entity_id definition_id, std::string name, std::unique_ptr type, 38 | cpp_storage_class_specifiers spec, bool is_constexpr, 39 | type_safe::optional semantic_parent = {}); 40 | 41 | /// \returns The [cppast::cpp_storage_specifiers]() on that variable. 42 | cpp_storage_class_specifiers storage_class() const noexcept 43 | { 44 | return storage_; 45 | } 46 | 47 | /// \returns Whether the variable is marked `constexpr`. 48 | bool is_constexpr() const noexcept 49 | { 50 | return is_constexpr_; 51 | } 52 | 53 | private: 54 | cpp_variable(std::string name, std::unique_ptr type, 55 | std::unique_ptr def, cpp_storage_class_specifiers spec, 56 | bool is_constexpr) 57 | : cpp_entity(std::move(name)), cpp_variable_base(std::move(type), std::move(def)), 58 | storage_(spec), is_constexpr_(is_constexpr) 59 | {} 60 | 61 | cpp_entity_kind do_get_entity_kind() const noexcept override; 62 | 63 | cpp_storage_class_specifiers storage_; 64 | bool is_constexpr_; 65 | }; 66 | } // namespace cppast 67 | 68 | #endif // CPPAST_CPP_VARIABLE_HPP_INCLUDED 69 | -------------------------------------------------------------------------------- /include/cppast/cpp_variable_base.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_VARIABLE_BASE_HPP_INCLUDED 5 | #define CPPAST_CPP_VARIABLE_BASE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// Additional base class for all [cppast::cpp_entity]() modelling some kind of variable. 13 | /// 14 | /// Examples are [cppast::cpp_variable]() or [cppast::cpp_function_parameter](), 15 | /// or anything that is name/type/default-value triple. 16 | class cpp_variable_base 17 | { 18 | public: 19 | /// \returns A reference to the [cppast::cpp_type]() of the variable. 20 | const cpp_type& type() const noexcept 21 | { 22 | return *type_; 23 | } 24 | 25 | /// \returns A [ts::optional_ref]() to the [cppast::cpp_expression]() that is the default value. 26 | type_safe::optional_ref default_value() const noexcept 27 | { 28 | return type_safe::opt_ref(default_.get()); 29 | } 30 | 31 | protected: 32 | cpp_variable_base(std::unique_ptr type, std::unique_ptr def) 33 | : type_(std::move(type)), default_(std::move(def)) 34 | {} 35 | 36 | ~cpp_variable_base() noexcept = default; 37 | 38 | private: 39 | std::unique_ptr type_; 40 | std::unique_ptr default_; 41 | }; 42 | } // namespace cppast 43 | 44 | #endif // CPPAST_CPP_VARIABLE_BASE_HPP_INCLUDED 45 | -------------------------------------------------------------------------------- /include/cppast/cpp_variable_template.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_CPP_VARIABLE_TEMPLATE_HPP_INCLUDED 5 | #define CPPAST_CPP_VARIABLE_TEMPLATE_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | /// A [cppast::cpp_entity]() modelling a C++ alias template. 13 | class cpp_variable_template final : public cpp_template 14 | { 15 | public: 16 | static cpp_entity_kind kind() noexcept; 17 | 18 | /// Builder for [cppast::cpp_variable_template](). 19 | class builder : public basic_builder 20 | { 21 | public: 22 | using basic_builder::basic_builder; 23 | }; 24 | 25 | /// \returns A reference to the type variable that is being templated. 26 | const cpp_variable& variable() const noexcept 27 | { 28 | return static_cast(*begin()); 29 | } 30 | 31 | private: 32 | cpp_variable_template(std::unique_ptr variable) 33 | : cpp_template(std::unique_ptr(variable.release())) 34 | {} 35 | 36 | cpp_entity_kind do_get_entity_kind() const noexcept override; 37 | 38 | friend basic_builder; 39 | }; 40 | } // namespace cppast 41 | 42 | #endif // CPPAST_CPP_VARIABLE_TEMPLATE_HPP_INCLUDED 43 | -------------------------------------------------------------------------------- /include/cppast/cppast_fwd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 Julian Rüth 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_FORWARD_HPP_INCLUDED 5 | #define CPPAST_FORWARD_HPP_INCLUDED 6 | 7 | namespace cppast 8 | { 9 | 10 | class code_generator; 11 | class compile_config; 12 | class cpp_access_specifier; 13 | class cpp_alias_template; 14 | class cpp_array_type; 15 | class cpp_attribute; 16 | class cpp_auto_type; 17 | class cpp_base_class; 18 | class cpp_bitfield; 19 | class cpp_builtin_type; 20 | class cpp_class; 21 | class cpp_class_template; 22 | class cpp_class_template_specialization; 23 | class cpp_concept; 24 | class cpp_constructor; 25 | class cpp_conversion_op; 26 | class cpp_cv_qualified_type; 27 | class cpp_decltype_auto_type; 28 | class cpp_decltype_type; 29 | class cpp_dependent_type; 30 | class cpp_destructor; 31 | class cpp_entity; 32 | class cpp_entity_index; 33 | class cpp_enum; 34 | class cpp_enum_value; 35 | class cpp_expression; 36 | class cpp_file; 37 | class cpp_forward_declarable; 38 | class cpp_friend; 39 | class cpp_function; 40 | class cpp_function_base; 41 | class cpp_function_parameter; 42 | class cpp_function_template; 43 | class cpp_function_template_specialization; 44 | class cpp_function_type; 45 | class cpp_include_directive; 46 | class cpp_language_linkage; 47 | class cpp_literal_expression; 48 | class cpp_macro_definition; 49 | class cpp_macro_parameter; 50 | class cpp_member_function; 51 | class cpp_member_function_base; 52 | class cpp_member_function_type; 53 | class cpp_member_object_type; 54 | class cpp_member_variable_base; 55 | class cpp_namespace; 56 | class cpp_non_type_template_parameter; 57 | class cpp_pointer_type; 58 | class cpp_reference_type; 59 | class cpp_scope_name; 60 | class cpp_static_assert; 61 | class cpp_template; 62 | class cpp_template_argument; 63 | class cpp_template_instantiation_type; 64 | class cpp_template_parameter; 65 | class cpp_template_parameter_type; 66 | class cpp_template_specialization; 67 | class cpp_template_template_parameter; 68 | class cpp_template_type_parameter; 69 | class cpp_token_string; 70 | class cpp_type; 71 | class cpp_type_alias; 72 | class cpp_unexposed_entity; 73 | class cpp_unexposed_expression; 74 | class cpp_unexposed_type; 75 | class cpp_user_defined_type; 76 | class cpp_using_declaration; 77 | class cpp_using_directive; 78 | class cpp_variable; 79 | class cpp_variable_base; 80 | class cpp_variable_template; 81 | class diagnostic_logger; 82 | class libclang_compilation_database; 83 | class libclang_compile_config; 84 | class libclang_error; 85 | class libclang_parser; 86 | class parser; 87 | class string_view; 88 | 89 | enum class compile_flag; 90 | enum class cpp_attribute_kind; 91 | enum class cpp_class_kind; 92 | enum class cpp_entity_kind; 93 | enum class cpp_expression_kind; 94 | enum class cpp_include_kind; 95 | enum class cpp_standard; 96 | enum class cpp_template_keyword; 97 | enum class cpp_token_kind; 98 | enum class cpp_type_kind; 99 | enum class cpp_virtual_flags; 100 | enum class formatting_flags; 101 | enum class severity; 102 | enum class visit_filter; 103 | 104 | enum cpp_access_specifier_kind : int; 105 | enum cpp_builtin_type_kind : int; 106 | enum cpp_cv : int; 107 | enum cpp_function_body_kind : int; 108 | enum cpp_reference : int; 109 | enum cpp_storage_class_specifiers : int; 110 | enum visitor_result : bool; 111 | 112 | struct cpp_doc_comment; 113 | struct cpp_entity_id; 114 | struct cpp_token; 115 | struct diagnostic; 116 | struct newl_t; 117 | struct source_location; 118 | struct visitor_info; 119 | struct whitespace_t; 120 | 121 | template 122 | class cpp_entity_container; 123 | template 124 | class simple_file_parser; 125 | template 126 | class basic_cpp_entity_ref; 127 | 128 | } // namespace cppast 129 | 130 | #endif // CPPAST_FORWARD_HPP_INCLUDED 131 | -------------------------------------------------------------------------------- /include/cppast/detail/assert.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_ASSERT_HPP_INCLUDED 5 | #define CPPAST_ASSERT_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #ifndef CPPAST_ASSERTION_LEVEL 10 | # define CPPAST_ASSERTION_LEVEL 0 11 | #endif 12 | 13 | #ifndef CPPAST_PRECONDITION_LEVEL 14 | # ifdef NDEBUG 15 | # define CPPAST_PRECONDITION_LEVEL 0 16 | # else 17 | # define CPPAST_PRECONDITION_LEVEL 1 18 | # endif 19 | #endif 20 | 21 | namespace cppast 22 | { 23 | namespace detail 24 | { 25 | struct assert_handler : debug_assert::set_level, 26 | debug_assert::default_handler 27 | {}; 28 | 29 | struct precondition_error_handler : debug_assert::set_level, 30 | debug_assert::default_handler 31 | {}; 32 | } // namespace detail 33 | } // namespace cppast 34 | 35 | #endif // CPPAST_ASSERT_HPP_INCLUDED 36 | -------------------------------------------------------------------------------- /include/cppast/diagnostic.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_DIAGNOSTIC_HPP_INCLUDED 5 | #define CPPAST_DIAGNOSTIC_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace cppast 15 | { 16 | /// Describes a physical source location attached to a [cppast::diagnostic](). 17 | /// \notes All information might be unavailable. 18 | struct source_location 19 | { 20 | type_safe::optional entity; 21 | type_safe::optional file; 22 | type_safe::optional line, column; 23 | 24 | /// \returns A source location where all information is available. 25 | static source_location make(std::string entity, std::string file, unsigned line, 26 | unsigned column) 27 | { 28 | return {std::move(entity), std::move(file), line, column}; 29 | } 30 | 31 | /// \returns A source location where only file information is available. 32 | static source_location make_file(std::string file, 33 | type_safe::optional line = type_safe::nullopt, 34 | type_safe::optional column = type_safe::nullopt) 35 | { 36 | return {type_safe::nullopt, std::move(file), line, column}; 37 | } 38 | 39 | /// \returns A source location where only the entity name is available. 40 | static source_location make_entity(std::string entity) 41 | { 42 | return {std::move(entity), type_safe::nullopt, type_safe::nullopt, type_safe::nullopt}; 43 | } 44 | 45 | /// \returns A source location where no information is avilable. 46 | static source_location make_unknown() 47 | { 48 | return {type_safe::nullopt, type_safe::nullopt, type_safe::nullopt, type_safe::nullopt}; 49 | } 50 | 51 | /// \returns A source location where entity and file name is available. 52 | static source_location make_entity(std::string entity, std::string file) 53 | { 54 | return {std::move(entity), std::move(file), type_safe::nullopt, type_safe::nullopt}; 55 | } 56 | 57 | /// \returns A possible string representation of the source location. 58 | /// \notes It will include a separator, but no trailing whitespace. 59 | std::string to_string() const 60 | { 61 | std::string result; 62 | if (file) 63 | { 64 | result += file.value() + ":"; 65 | 66 | if (line) 67 | { 68 | result += std::to_string(line.value()); 69 | 70 | if (column) 71 | result += "," + std::to_string(column.value()); 72 | 73 | result += ":"; 74 | } 75 | 76 | if (entity) 77 | result += " (" + entity.value() + "):"; 78 | } 79 | else if (entity && !entity.value().empty()) 80 | result += entity.value() + ":"; 81 | 82 | return result; 83 | } 84 | }; 85 | 86 | /// The severity of a [cppast::diagnostic](). 87 | enum class severity 88 | { 89 | debug, //< A debug diagnostic that is just for debugging purposes. 90 | info, //< An informational message. 91 | warning, //< A warning that doesn't impact AST generation. 92 | error, //< A non-critical error that does impact AST generation but not critically. 93 | critical, //< A critical error where AST generation isn't possible. 94 | /// \notes This will usually result in an exception being thrown after the diagnostic has been 95 | /// displayed. 96 | }; 97 | 98 | /// \returns A human-readable string describing the severity. 99 | inline const char* to_string(severity s) noexcept 100 | { 101 | switch (s) 102 | { 103 | case severity::debug: 104 | return "debug"; 105 | case severity::info: 106 | return "info"; 107 | case severity::warning: 108 | return "warning"; 109 | case severity::error: 110 | return "error"; 111 | case severity::critical: 112 | return "critical"; 113 | } 114 | 115 | return "programmer error"; 116 | } 117 | 118 | /// A diagnostic. 119 | /// 120 | /// It represents an error message from a [cppast::parser](). 121 | struct diagnostic 122 | { 123 | std::string message; 124 | source_location location; 125 | cppast::severity severity; 126 | }; 127 | 128 | namespace detail 129 | { 130 | template 131 | std::string format(Args&&... args) 132 | { 133 | std::ostringstream stream; 134 | int dummy[] = {(stream << std::forward(args), 0)...}; 135 | (void)dummy; 136 | return stream.str(); 137 | } 138 | } // namespace detail 139 | 140 | /// Creates a diagnostic. 141 | /// \returns A diagnostic with the specified severity and location. 142 | /// The message is created by streaming each argument in order to a [std::ostringstream](). 143 | template 144 | diagnostic format_diagnostic(severity sev, source_location loc, Args&&... args) 145 | { 146 | return {detail::format(std::forward(args)...), std::move(loc), sev}; 147 | } 148 | } // namespace cppast 149 | 150 | #endif // CPPAST_DIAGNOSTIC_HPP_INCLUDED 151 | -------------------------------------------------------------------------------- /include/cppast/diagnostic_logger.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_DIAGNOSTIC_LOGGER_HPP_INCLUDED 5 | #define CPPAST_DIAGNOSTIC_LOGGER_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace cppast 12 | { 13 | /// Base class for a [cppast::diagnostic]() logger. 14 | /// 15 | /// Its task is controlling how diagnostic are being displayed. 16 | class diagnostic_logger 17 | { 18 | public: 19 | /// \effects Creates it either as verbose or not. 20 | explicit diagnostic_logger(bool is_verbose = false) noexcept : verbose_(is_verbose) {} 21 | 22 | diagnostic_logger(const diagnostic_logger&) = delete; 23 | diagnostic_logger& operator=(const diagnostic_logger&) = delete; 24 | virtual ~diagnostic_logger() noexcept = default; 25 | 26 | /// \effects Logs the diagnostic by invoking the `do_log()` member function. 27 | /// \returns Whether or not the diagnostic was logged. 28 | /// \notes `source` points to a string literal that gives additional context to what generates 29 | /// the message. 30 | bool log(const char* source, const diagnostic& d) const; 31 | 32 | /// \effects Sets whether or not the logger prints debugging diagnostics. 33 | void set_verbose(bool value) noexcept 34 | { 35 | verbose_ = value; 36 | } 37 | 38 | /// \returns Whether or not the logger prints debugging diagnostics. 39 | bool is_verbose() const noexcept 40 | { 41 | return verbose_; 42 | } 43 | 44 | private: 45 | virtual bool do_log(const char* source, const diagnostic& d) const = 0; 46 | 47 | bool verbose_; 48 | }; 49 | 50 | /// \returns The default logger object. 51 | type_safe::object_ref default_logger() noexcept; 52 | 53 | /// \returns The default verbose logger object. 54 | type_safe::object_ref default_verbose_logger() noexcept; 55 | 56 | /// A [cppast::diagnostic_logger]() that logs to `stderr`. 57 | /// 58 | /// It prints all diagnostics in an implementation-defined format. 59 | class stderr_diagnostic_logger final : public diagnostic_logger 60 | { 61 | public: 62 | using diagnostic_logger::diagnostic_logger; 63 | 64 | private: 65 | bool do_log(const char* source, const diagnostic& d) const override; 66 | }; 67 | } // namespace cppast 68 | 69 | #endif // CPPAST_DIAGNOSTIC_LOGGER_HPP_INCLUDED 70 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | # SPDX-License-Identifier: MIT 3 | # found in the top-level directory of this distribution. 4 | 5 | set(detail_header 6 | ../include/cppast/detail/assert.hpp 7 | ../include/cppast/detail/intrusive_list.hpp) 8 | set(header 9 | ../include/cppast/code_generator.hpp 10 | ../include/cppast/compile_config.hpp 11 | ../include/cppast/cpp_alias_template.hpp 12 | ../include/cppast/cpp_array_type.hpp 13 | ../include/cppast/cpp_attribute.hpp 14 | ../include/cppast/cpp_class.hpp 15 | ../include/cppast/cpp_class_template.hpp 16 | ../include/cppast/cpp_concept.hpp 17 | ../include/cppast/cpp_decltype_type.hpp 18 | ../include/cppast/cpp_entity.hpp 19 | ../include/cppast/cpp_entity_container.hpp 20 | ../include/cppast/cpp_entity_index.hpp 21 | ../include/cppast/cpp_entity_kind.hpp 22 | ../include/cppast/cpp_entity_ref.hpp 23 | ../include/cppast/cpp_enum.hpp 24 | ../include/cppast/cpp_expression.hpp 25 | ../include/cppast/cpp_file.hpp 26 | ../include/cppast/cpp_forward_declarable.hpp 27 | ../include/cppast/cpp_friend.hpp 28 | ../include/cppast/cpp_function.hpp 29 | ../include/cppast/cpp_function_template.hpp 30 | ../include/cppast/cpp_function_type.hpp 31 | ../include/cppast/cpp_language_linkage.hpp 32 | ../include/cppast/cpp_member_function.hpp 33 | ../include/cppast/cpp_member_variable.hpp 34 | ../include/cppast/cpp_namespace.hpp 35 | ../include/cppast/cpp_preprocessor.hpp 36 | ../include/cppast/cpp_static_assert.hpp 37 | ../include/cppast/cpp_storage_class_specifiers.hpp 38 | ../include/cppast/cpp_template.hpp 39 | ../include/cppast/cpp_template_parameter.hpp 40 | ../include/cppast/cpp_token.hpp 41 | ../include/cppast/cpp_type.hpp 42 | ../include/cppast/cpp_type_alias.hpp 43 | ../include/cppast/cpp_variable.hpp 44 | ../include/cppast/cpp_variable_base.hpp 45 | ../include/cppast/cpp_variable_template.hpp 46 | ../include/cppast/diagnostic.hpp 47 | ../include/cppast/diagnostic_logger.hpp 48 | ../include/cppast/cppast_fwd.hpp 49 | ../include/cppast/libclang_parser.hpp 50 | ../include/cppast/parser.hpp 51 | ../include/cppast/visitor.hpp) 52 | set(source 53 | code_generator.cpp 54 | cpp_alias_template.cpp 55 | cpp_attribute.cpp 56 | cpp_class.cpp 57 | cpp_class_template.cpp 58 | cpp_concept.cpp 59 | cpp_entity.cpp 60 | cpp_entity_index.cpp 61 | cpp_entity_kind.cpp 62 | cpp_enum.cpp 63 | cpp_expression.cpp 64 | cpp_file.cpp 65 | cpp_forward_declarable.cpp 66 | cpp_friend.cpp 67 | cpp_function.cpp 68 | cpp_function_template.cpp 69 | cpp_language_linkage.cpp 70 | cpp_member_function.cpp 71 | cpp_member_variable.cpp 72 | cpp_namespace.cpp 73 | cpp_preprocessor.cpp 74 | cpp_static_assert.cpp 75 | cpp_template_parameter.cpp 76 | cpp_token.cpp 77 | cpp_type.cpp 78 | cpp_type_alias.cpp 79 | cpp_variable.cpp 80 | cpp_variable_template.cpp 81 | diagnostic_logger.cpp 82 | visitor.cpp) 83 | set(libclang_source 84 | libclang/class_parser.cpp 85 | libclang/concept_parser.cpp 86 | libclang/cxtokenizer.cpp 87 | libclang/cxtokenizer.hpp 88 | libclang/debug_helper.cpp 89 | libclang/debug_helper.hpp 90 | libclang/enum_parser.cpp 91 | libclang/expression_parser.cpp 92 | libclang/friend_parser.cpp 93 | libclang/function_parser.cpp 94 | libclang/language_linkage_parser.cpp 95 | libclang/libclang_parser.cpp 96 | libclang/libclang_visitor.hpp 97 | libclang/namespace_parser.cpp 98 | libclang/parse_error.hpp 99 | libclang/parse_functions.cpp 100 | libclang/parse_functions.hpp 101 | libclang/preprocessor.cpp 102 | libclang/preprocessor.hpp 103 | libclang/raii_wrapper.hpp 104 | libclang/template_parser.cpp 105 | libclang/type_parser.cpp 106 | libclang/variable_parser.cpp) 107 | 108 | add_library(cppast ${detail_header} ${header} ${source} ${libclang_source}) 109 | target_compile_features(cppast PUBLIC cxx_std_11) 110 | target_include_directories(cppast PRIVATE ../include SYSTEM INTERFACE ../include) 111 | target_link_libraries(cppast PUBLIC type_safe _cppast_tiny_process _cppast_libclang) 112 | target_compile_definitions(cppast PUBLIC 113 | CPPAST_VERSION_MINOR="${cppast_VERSION_MINOR}" 114 | CPPAST_VERSION_MAJOR="${cppast_VERSION_MAJOR}" 115 | CPPAST_VERSION_STRING="${cppast_VERSION}") 116 | 117 | if(${is_top_level_project}) 118 | target_compile_options(cppast PRIVATE 119 | # clang/GCC warnings 120 | $<$,$>: 121 | -pedantic-errors -Werror -Wall -Wextra -Wconversion -Wsign-conversion> 122 | # disable noexcept type warning on GCC 123 | $<$: -Wno-noexcept-type> 124 | # MSVC warnings 125 | $<$: 126 | /W3>) 127 | endif() 128 | 129 | install(TARGETS cppast) 130 | install(DIRECTORY ../include/ DESTINATION include) 131 | -------------------------------------------------------------------------------- /src/cpp_alias_template.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_alias_template::kind() noexcept 11 | { 12 | return cpp_entity_kind::alias_template_t; 13 | } 14 | 15 | cpp_entity_kind cpp_alias_template::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | -------------------------------------------------------------------------------- /src/cpp_attribute.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | using namespace cppast; 11 | 12 | namespace 13 | { 14 | const char* get_attribute_name(cpp_attribute_kind kind) noexcept 15 | { 16 | switch (kind) 17 | { 18 | case cpp_attribute_kind::alignas_: 19 | return "alignas"; 20 | case cpp_attribute_kind::carries_dependency: 21 | return "carries_dependency"; 22 | case cpp_attribute_kind::deprecated: 23 | return "deprecated"; 24 | case cpp_attribute_kind::fallthrough: 25 | return "fallthrough"; 26 | case cpp_attribute_kind::maybe_unused: 27 | return "maybe_unused"; 28 | case cpp_attribute_kind::nodiscard: 29 | return "nodiscard"; 30 | case cpp_attribute_kind::noreturn: 31 | return "noreturn"; 32 | 33 | case cpp_attribute_kind::unknown: 34 | return "unknown"; 35 | } 36 | 37 | return ""; 38 | } 39 | } // namespace 40 | 41 | cpp_attribute::cpp_attribute(cpp_attribute_kind kind, 42 | type_safe::optional arguments) 43 | : cpp_attribute(type_safe::nullopt, get_attribute_name(kind), std::move(arguments), false) 44 | { 45 | kind_ = kind; 46 | } 47 | 48 | type_safe::optional_ref cppast::has_attribute( 49 | const cpp_attribute_list& attributes, const std::string& name) 50 | { 51 | auto iter 52 | = std::find_if(attributes.begin(), attributes.end(), [&](const cpp_attribute& attribute) { 53 | if (attribute.scope()) 54 | return attribute.scope().value() + "::" + attribute.name() == name; 55 | else 56 | return attribute.name() == name; 57 | }); 58 | 59 | if (iter == attributes.end()) 60 | return nullptr; 61 | else 62 | return type_safe::ref(*iter); 63 | } 64 | 65 | type_safe::optional_ref cppast::has_attribute( 66 | const cpp_attribute_list& attributes, cpp_attribute_kind kind) 67 | { 68 | auto iter 69 | = std::find_if(attributes.begin(), attributes.end(), 70 | [&](const cpp_attribute& attribute) { return attribute.kind() == kind; }); 71 | 72 | if (iter == attributes.end()) 73 | return nullptr; 74 | else 75 | return type_safe::ref(*iter); 76 | } 77 | 78 | type_safe::optional_ref cppast::has_attribute(const cpp_entity& e, 79 | const std::string& name) 80 | { 81 | return has_attribute(e.attributes(), name); 82 | } 83 | 84 | type_safe::optional_ref cppast::has_attribute(const cpp_entity& e, 85 | cpp_attribute_kind kind) 86 | { 87 | return has_attribute(e.attributes(), kind); 88 | } 89 | -------------------------------------------------------------------------------- /src/cpp_class_template.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_class_template::kind() noexcept 11 | { 12 | return cpp_entity_kind::class_template_t; 13 | } 14 | 15 | cpp_entity_kind cpp_class_template::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | 20 | cpp_entity_kind cpp_class_template_specialization::kind() noexcept 21 | { 22 | return cpp_entity_kind::class_template_specialization_t; 23 | } 24 | 25 | cpp_entity_kind cpp_class_template_specialization::do_get_entity_kind() const noexcept 26 | { 27 | return kind(); 28 | } 29 | -------------------------------------------------------------------------------- /src/cpp_concept.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cppast::cpp_concept::kind() noexcept 11 | { 12 | return cpp_entity_kind::concept_t; 13 | } 14 | 15 | cpp_entity_kind cpp_concept::do_get_entity_kind() const noexcept 16 | { 17 | return cpp_entity_kind::concept_t; 18 | } 19 | 20 | std::unique_ptr cpp_concept::builder::finish(const cpp_entity_index& idx, 21 | cpp_entity_id id) 22 | { 23 | idx.register_definition(id, type_safe::ref(*concept_)); 24 | return std::move(concept_); 25 | } 26 | -------------------------------------------------------------------------------- /src/cpp_entity.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace cppast; 11 | 12 | cpp_scope_name::cpp_scope_name(type_safe::object_ref entity) : entity_(entity) 13 | { 14 | if (cppast::is_templated(*entity)) 15 | { 16 | auto& templ = static_cast(entity->parent().value()); 17 | if (!templ.parameters().empty()) 18 | templ_ = type_safe::ref(templ); 19 | } 20 | else if (is_template(entity->kind())) 21 | { 22 | auto& templ = static_cast(*entity); 23 | if (!templ.parameters().empty()) 24 | templ_ = type_safe::ref(templ); 25 | } 26 | } 27 | 28 | const std::string& cpp_scope_name::name() const noexcept 29 | { 30 | return entity_->name(); 31 | } 32 | 33 | detail::iteratable_intrusive_list cpp_scope_name::template_parameters() 34 | const noexcept 35 | { 36 | DEBUG_ASSERT(is_templated(), detail::precondition_error_handler{}); 37 | return templ_.value().parameters(); 38 | } 39 | 40 | cpp_entity_kind cpp_unexposed_entity::kind() noexcept 41 | { 42 | return cpp_entity_kind::unexposed_t; 43 | } 44 | 45 | std::unique_ptr cpp_unexposed_entity::build(const cpp_entity_index& index, 46 | cpp_entity_id id, std::string name, 47 | cpp_token_string spelling) 48 | { 49 | std::unique_ptr result( 50 | new cpp_unexposed_entity(std::move(name), std::move(spelling))); 51 | index.register_forward_declaration(id, type_safe::ref(*result)); 52 | return result; 53 | } 54 | 55 | std::unique_ptr cpp_unexposed_entity::build(cpp_token_string spelling) 56 | { 57 | return std::unique_ptr(new cpp_unexposed_entity("", std::move(spelling))); 58 | } 59 | 60 | cpp_entity_kind cpp_unexposed_entity::do_get_entity_kind() const noexcept 61 | { 62 | return kind(); 63 | } 64 | 65 | bool cppast::is_templated(const cpp_entity& e) noexcept 66 | { 67 | if (!e.parent()) 68 | return false; 69 | else if (!is_template(e.parent().value().kind())) 70 | return false; 71 | return e.parent().value().name() == e.name(); 72 | } 73 | -------------------------------------------------------------------------------- /src/cpp_entity_index.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace cppast; 12 | 13 | cpp_entity_index::duplicate_definition_error::duplicate_definition_error() 14 | : std::logic_error("duplicate registration of entity definition") 15 | {} 16 | 17 | void cpp_entity_index::register_definition(cpp_entity_id id, 18 | type_safe::object_ref entity) const 19 | { 20 | DEBUG_ASSERT(entity->kind() != cpp_entity_kind::namespace_t, 21 | detail::precondition_error_handler{}, "must not be a namespace"); 22 | std::lock_guard lock(mutex_); 23 | auto result = map_.emplace(std::move(id), value(entity, true)); 24 | if (!result.second) 25 | { 26 | // already in map, override declaration 27 | auto& value = result.first->second; 28 | if (value.is_definition && !is_template(value.entity->kind()) && entity->parent() 29 | && !is_template(entity->parent().value().kind())) 30 | // allow duplicate definition of templates 31 | // this handles things such as SFINAE 32 | throw duplicate_definition_error(); 33 | value.is_definition = true; 34 | value.entity = entity; 35 | } 36 | } 37 | 38 | bool cpp_entity_index::register_file(cpp_entity_id id, 39 | type_safe::object_ref file) const 40 | { 41 | std::lock_guard lock(mutex_); 42 | return map_.emplace(std::move(id), value(file, true)).second; 43 | } 44 | 45 | void cpp_entity_index::register_forward_declaration( 46 | cpp_entity_id id, type_safe::object_ref entity) const 47 | { 48 | std::lock_guard lock(mutex_); 49 | map_.emplace(std::move(id), value(entity, false)); 50 | } 51 | 52 | void cpp_entity_index::register_namespace(cpp_entity_id id, 53 | type_safe::object_ref ns) const 54 | { 55 | std::lock_guard lock(mutex_); 56 | ns_[std::move(id)].push_back(ns); 57 | } 58 | 59 | type_safe::optional_ref cpp_entity_index::lookup( 60 | const cpp_entity_id& id) const noexcept 61 | { 62 | std::lock_guard lock(mutex_); 63 | auto iter = map_.find(id); 64 | if (iter == map_.end()) 65 | return {}; 66 | return type_safe::ref(iter->second.entity.get()); 67 | } 68 | 69 | type_safe::optional_ref cpp_entity_index::lookup_definition( 70 | const cpp_entity_id& id) const noexcept 71 | { 72 | std::lock_guard lock(mutex_); 73 | auto iter = map_.find(id); 74 | if (iter == map_.end() || !iter->second.is_definition) 75 | return {}; 76 | return type_safe::ref(iter->second.entity.get()); 77 | } 78 | 79 | auto cpp_entity_index::lookup_namespace(const cpp_entity_id& id) const noexcept 80 | -> type_safe::array_ref> 81 | { 82 | std::lock_guard lock(mutex_); 83 | auto iter = ns_.find(id); 84 | if (iter == ns_.end()) 85 | return nullptr; 86 | auto& vec = iter->second; 87 | return type_safe::ref(vec.data(), vec.size()); 88 | } 89 | -------------------------------------------------------------------------------- /src/cpp_enum.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_enum_value::kind() noexcept 11 | { 12 | return cpp_entity_kind::enum_value_t; 13 | } 14 | 15 | std::unique_ptr cpp_enum_value::build(const cpp_entity_index& idx, cpp_entity_id id, 16 | std::string name, 17 | std::unique_ptr value) 18 | { 19 | auto result 20 | = std::unique_ptr(new cpp_enum_value(std::move(name), std::move(value))); 21 | idx.register_definition(std::move(id), type_safe::ref(*result)); 22 | return result; 23 | } 24 | 25 | cpp_entity_kind cpp_enum_value::do_get_entity_kind() const noexcept 26 | { 27 | return kind(); 28 | } 29 | 30 | cpp_entity_kind cpp_enum::kind() noexcept 31 | { 32 | return cpp_entity_kind::enum_t; 33 | } 34 | 35 | cpp_entity_kind cpp_enum::do_get_entity_kind() const noexcept 36 | { 37 | return kind(); 38 | } 39 | 40 | type_safe::optional cpp_enum::do_get_scope_name() const 41 | { 42 | if (scoped_) 43 | return type_safe::ref(*this); 44 | return type_safe::nullopt; 45 | } 46 | -------------------------------------------------------------------------------- /src/cpp_expression.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | using namespace cppast; 7 | 8 | namespace 9 | { 10 | void write_literal(code_generator::output& output, const cpp_literal_expression& expr) 11 | { 12 | auto type_kind = cpp_void; 13 | if (expr.type().kind() == cpp_type_kind::builtin_t) 14 | type_kind = static_cast(expr.type()).builtin_type_kind(); 15 | else if (expr.type().kind() == cpp_type_kind::pointer_t) 16 | { 17 | auto& pointee = static_cast(expr.type()).pointee(); 18 | if (pointee.kind() == cpp_type_kind::builtin_t) 19 | { 20 | auto& builtin_pointee = static_cast(pointee); 21 | if (builtin_pointee.builtin_type_kind() == cpp_char 22 | || builtin_pointee.builtin_type_kind() == cpp_wchar 23 | || builtin_pointee.builtin_type_kind() == cpp_char16 24 | || builtin_pointee.builtin_type_kind() == cpp_char32) 25 | // pointer to char aka string 26 | type_kind = builtin_pointee.builtin_type_kind(); 27 | } 28 | } 29 | 30 | switch (type_kind) 31 | { 32 | case cpp_void: 33 | output << token_seq(expr.value()); 34 | break; 35 | 36 | case cpp_bool: 37 | output << keyword(expr.value()); 38 | break; 39 | 40 | case cpp_uchar: 41 | case cpp_ushort: 42 | case cpp_uint: 43 | case cpp_ulong: 44 | case cpp_ulonglong: 45 | case cpp_uint128: 46 | case cpp_schar: 47 | case cpp_short: 48 | case cpp_int: 49 | case cpp_long: 50 | case cpp_longlong: 51 | case cpp_int128: 52 | output << int_literal(expr.value()); 53 | break; 54 | 55 | case cpp_float: 56 | case cpp_double: 57 | case cpp_longdouble: 58 | case cpp_float128: 59 | output << float_literal(expr.value()); 60 | break; 61 | 62 | case cpp_char: 63 | case cpp_wchar: 64 | case cpp_char16: 65 | case cpp_char32: 66 | output << string_literal(expr.value()); 67 | break; 68 | 69 | case cpp_nullptr: 70 | output << keyword(expr.value()); 71 | break; 72 | } 73 | } 74 | 75 | void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr) 76 | { 77 | detail::write_token_string(output, expr.expression()); 78 | } 79 | } // namespace 80 | 81 | void detail::write_expression(code_generator::output& output, const cpp_expression& expr) 82 | { 83 | switch (expr.kind()) 84 | { 85 | case cpp_expression_kind::literal_t: 86 | write_literal(output, static_cast(expr)); 87 | break; 88 | case cpp_expression_kind::unexposed_t: 89 | write_unexposed(output, static_cast(expr)); 90 | break; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/cpp_file.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_file::kind() noexcept 11 | { 12 | return cpp_entity_kind::file_t; 13 | } 14 | 15 | cpp_entity_kind cpp_file::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | 20 | bool detail::cpp_file_ref_predicate::operator()(const cpp_entity& e) 21 | { 22 | return e.kind() == cpp_entity_kind::file_t; 23 | } 24 | -------------------------------------------------------------------------------- /src/cpp_friend.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_friend::kind() noexcept 11 | { 12 | return cpp_entity_kind::friend_t; 13 | } 14 | 15 | cpp_entity_kind cpp_friend::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | 20 | bool cppast::is_friended(const cpp_entity& e) noexcept 21 | { 22 | if (is_templated(e)) 23 | return is_friended(e.parent().value()); 24 | return e.parent() && e.parent().value().kind() == cpp_entity_kind::friend_t; 25 | } 26 | -------------------------------------------------------------------------------- /src/cpp_function.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_function_parameter::kind() noexcept 11 | { 12 | return cpp_entity_kind::function_parameter_t; 13 | } 14 | 15 | std::unique_ptr cpp_function_parameter::build( 16 | const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, 17 | std::unique_ptr def) 18 | { 19 | auto result = std::unique_ptr( 20 | new cpp_function_parameter(std::move(name), std::move(type), std::move(def))); 21 | idx.register_definition(std::move(id), type_safe::cref(*result)); 22 | return result; 23 | } 24 | 25 | std::unique_ptr cpp_function_parameter::build( 26 | std::unique_ptr type, std::unique_ptr def) 27 | { 28 | return std::unique_ptr( 29 | new cpp_function_parameter("", std::move(type), std::move(def))); 30 | } 31 | 32 | cpp_entity_kind cpp_function_parameter::do_get_entity_kind() const noexcept 33 | { 34 | return kind(); 35 | } 36 | 37 | std::string cpp_function_base::do_get_signature() const 38 | { 39 | std::string result = "("; 40 | for (auto& param : parameters()) 41 | result += to_string(param.type()) + ','; 42 | if (is_variadic()) 43 | result += "..."; 44 | 45 | if (result.back() == ',') 46 | result.back() = ')'; 47 | else 48 | result.push_back(')'); 49 | 50 | return result; 51 | } 52 | 53 | cpp_entity_kind cpp_function::kind() noexcept 54 | { 55 | return cpp_entity_kind::function_t; 56 | } 57 | 58 | cpp_entity_kind cpp_function::do_get_entity_kind() const noexcept 59 | { 60 | return kind(); 61 | } 62 | -------------------------------------------------------------------------------- /src/cpp_function_template.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_function_template::kind() noexcept 11 | { 12 | return cpp_entity_kind::function_template_t; 13 | } 14 | 15 | cpp_entity_kind cpp_function_template::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | 20 | cpp_entity_kind cpp_function_template_specialization::kind() noexcept 21 | { 22 | return cpp_entity_kind::function_template_specialization_t; 23 | } 24 | 25 | cpp_entity_kind cpp_function_template_specialization::do_get_entity_kind() const noexcept 26 | { 27 | return kind(); 28 | } 29 | -------------------------------------------------------------------------------- /src/cpp_language_linkage.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_language_linkage::kind() noexcept 11 | { 12 | return cpp_entity_kind::language_linkage_t; 13 | } 14 | 15 | bool cpp_language_linkage::is_block() const noexcept 16 | { 17 | if (begin() == end()) 18 | { 19 | // An empty container must be a "block" of the form: extern "C" {} 20 | return true; 21 | } 22 | return std::next(begin()) != end(); // more than one entity, so block 23 | } 24 | 25 | cpp_entity_kind cpp_language_linkage::do_get_entity_kind() const noexcept 26 | { 27 | return kind(); 28 | } 29 | -------------------------------------------------------------------------------- /src/cpp_member_function.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | std::string cpp_member_function_base::do_get_signature() const 11 | { 12 | auto result = cpp_function_base::do_get_signature(); 13 | 14 | if (is_const(cv_qualifier())) 15 | result += " const"; 16 | if (is_volatile(cv_qualifier())) 17 | result += " volatile"; 18 | 19 | if (ref_qualifier() == cpp_ref_lvalue) 20 | result += " &"; 21 | else if (ref_qualifier() == cpp_ref_rvalue) 22 | result += " &&"; 23 | 24 | return result; 25 | } 26 | 27 | cpp_entity_kind cpp_member_function::kind() noexcept 28 | { 29 | return cpp_entity_kind::member_function_t; 30 | } 31 | 32 | cpp_entity_kind cpp_member_function::do_get_entity_kind() const noexcept 33 | { 34 | return kind(); 35 | } 36 | 37 | cpp_entity_kind cpp_conversion_op::kind() noexcept 38 | { 39 | return cpp_entity_kind::conversion_op_t; 40 | } 41 | 42 | cpp_entity_kind cpp_conversion_op::do_get_entity_kind() const noexcept 43 | { 44 | return kind(); 45 | } 46 | 47 | cpp_entity_kind cpp_constructor::kind() noexcept 48 | { 49 | return cpp_entity_kind::constructor_t; 50 | } 51 | 52 | cpp_entity_kind cpp_constructor::do_get_entity_kind() const noexcept 53 | { 54 | return kind(); 55 | } 56 | 57 | cpp_entity_kind cpp_destructor::kind() noexcept 58 | { 59 | return cpp_entity_kind::destructor_t; 60 | } 61 | 62 | cpp_entity_kind cpp_destructor::do_get_entity_kind() const noexcept 63 | { 64 | return kind(); 65 | } 66 | -------------------------------------------------------------------------------- /src/cpp_member_variable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_member_variable::kind() noexcept 11 | { 12 | return cpp_entity_kind::member_variable_t; 13 | } 14 | 15 | std::unique_ptr cpp_member_variable::build(const cpp_entity_index& idx, 16 | cpp_entity_id id, std::string name, 17 | std::unique_ptr type, 18 | std::unique_ptr def, 19 | bool is_mutable) 20 | { 21 | auto result = std::unique_ptr( 22 | new cpp_member_variable(std::move(name), std::move(type), std::move(def), is_mutable)); 23 | idx.register_definition(std::move(id), type_safe::cref(*result)); 24 | return result; 25 | } 26 | 27 | cpp_entity_kind cpp_member_variable::do_get_entity_kind() const noexcept 28 | { 29 | return kind(); 30 | } 31 | 32 | cpp_entity_kind cpp_bitfield::kind() noexcept 33 | { 34 | return cpp_entity_kind::bitfield_t; 35 | } 36 | 37 | std::unique_ptr cpp_bitfield::build(const cpp_entity_index& idx, cpp_entity_id id, 38 | std::string name, std::unique_ptr type, 39 | unsigned no_bits, bool is_mutable) 40 | { 41 | auto result = std::unique_ptr( 42 | new cpp_bitfield(std::move(name), std::move(type), no_bits, is_mutable)); 43 | idx.register_definition(std::move(id), type_safe::cref(*result)); 44 | return result; 45 | } 46 | 47 | std::unique_ptr cpp_bitfield::build(std::unique_ptr type, unsigned no_bits, 48 | bool is_mutable) 49 | { 50 | return std::unique_ptr( 51 | new cpp_bitfield("", std::move(type), no_bits, is_mutable)); 52 | } 53 | 54 | cpp_entity_kind cpp_bitfield::do_get_entity_kind() const noexcept 55 | { 56 | return kind(); 57 | } 58 | -------------------------------------------------------------------------------- /src/cpp_namespace.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_namespace::kind() noexcept 11 | { 12 | return cpp_entity_kind::namespace_t; 13 | } 14 | 15 | cpp_entity_kind cpp_namespace::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | 20 | bool detail::cpp_namespace_ref_predicate::operator()(const cpp_entity& e) 21 | { 22 | return e.kind() == cpp_entity_kind::namespace_t; 23 | } 24 | 25 | std::unique_ptr cpp_namespace_alias::build(const cpp_entity_index& idx, 26 | cpp_entity_id id, std::string name, 27 | cpp_namespace_ref target) 28 | { 29 | auto ptr = std::unique_ptr( 30 | new cpp_namespace_alias(std::move(name), std::move(target))); 31 | idx.register_forward_declaration(std::move(id), type_safe::ref(*ptr)); 32 | return ptr; 33 | } 34 | 35 | cpp_entity_kind cpp_namespace_alias::kind() noexcept 36 | { 37 | return cpp_entity_kind::namespace_alias_t; 38 | } 39 | 40 | cpp_entity_kind cpp_namespace_alias::do_get_entity_kind() const noexcept 41 | { 42 | return kind(); 43 | } 44 | 45 | cpp_entity_kind cpp_using_directive::kind() noexcept 46 | { 47 | return cpp_entity_kind::using_directive_t; 48 | } 49 | 50 | cpp_entity_kind cpp_using_directive::do_get_entity_kind() const noexcept 51 | { 52 | return kind(); 53 | } 54 | 55 | cpp_entity_kind cpp_using_declaration::kind() noexcept 56 | { 57 | return cpp_entity_kind::using_declaration_t; 58 | } 59 | 60 | cpp_entity_kind cpp_using_declaration::do_get_entity_kind() const noexcept 61 | { 62 | return kind(); 63 | } 64 | -------------------------------------------------------------------------------- /src/cpp_preprocessor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_macro_parameter::kind() noexcept 11 | { 12 | return cpp_entity_kind::macro_parameter_t; 13 | } 14 | 15 | cpp_entity_kind cpp_macro_parameter::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | 20 | cpp_entity_kind cpp_macro_definition::kind() noexcept 21 | { 22 | return cpp_entity_kind::macro_definition_t; 23 | } 24 | 25 | cpp_entity_kind cpp_macro_definition::do_get_entity_kind() const noexcept 26 | { 27 | return kind(); 28 | } 29 | 30 | cpp_entity_kind cpp_include_directive::kind() noexcept 31 | { 32 | return cpp_entity_kind::include_directive_t; 33 | } 34 | 35 | cpp_entity_kind cpp_include_directive::do_get_entity_kind() const noexcept 36 | { 37 | return kind(); 38 | } 39 | -------------------------------------------------------------------------------- /src/cpp_static_assert.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cppast::cpp_entity_kind cpp_static_assert::kind() noexcept 11 | { 12 | return cpp_entity_kind::static_assert_t; 13 | } 14 | 15 | cppast::cpp_entity_kind cpp_static_assert::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | -------------------------------------------------------------------------------- /src/cpp_template_parameter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | const char* cppast::to_string(cpp_template_keyword kw) noexcept 11 | { 12 | switch (kw) 13 | { 14 | case cpp_template_keyword::keyword_class: 15 | return "class"; 16 | case cpp_template_keyword::keyword_typename: 17 | return "typename"; 18 | case cpp_template_keyword::concept_contraint: 19 | return "concept constraint data lost"; 20 | } 21 | 22 | return "should not get here"; 23 | } 24 | 25 | std::unique_ptr cpp_template_type_parameter::build( 26 | const cpp_entity_index& idx, cpp_entity_id id, std::string name, cpp_template_keyword kw, 27 | bool variadic, std::unique_ptr default_type, 28 | type_safe::optional concept_constraint) 29 | { 30 | std::unique_ptr result( 31 | new cpp_template_type_parameter(std::move(name), kw, variadic, std::move(default_type), 32 | std::move(concept_constraint))); 33 | idx.register_definition(std::move(id), type_safe::cref(*result)); 34 | return result; 35 | } 36 | 37 | cpp_entity_kind cpp_template_type_parameter::kind() noexcept 38 | { 39 | return cpp_entity_kind::template_type_parameter_t; 40 | } 41 | 42 | cpp_entity_kind cpp_template_type_parameter::do_get_entity_kind() const noexcept 43 | { 44 | return kind(); 45 | } 46 | 47 | bool detail::cpp_template_parameter_ref_predicate::operator()(const cpp_entity& e) 48 | { 49 | return e.kind() == cpp_entity_kind::template_type_parameter_t; 50 | } 51 | 52 | std::unique_ptr cpp_non_type_template_parameter::build( 53 | const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, 54 | bool is_variadic, std::unique_ptr default_value) 55 | { 56 | std::unique_ptr result( 57 | new cpp_non_type_template_parameter(std::move(name), std::move(type), is_variadic, 58 | std::move(default_value))); 59 | idx.register_definition(std::move(id), type_safe::cref(*result)); 60 | return result; 61 | } 62 | 63 | cpp_entity_kind cpp_non_type_template_parameter::kind() noexcept 64 | { 65 | return cpp_entity_kind::non_type_template_parameter_t; 66 | } 67 | 68 | cpp_entity_kind cpp_non_type_template_parameter::do_get_entity_kind() const noexcept 69 | { 70 | return kind(); 71 | } 72 | 73 | bool detail::cpp_template_ref_predicate::operator()(const cpp_entity& e) 74 | { 75 | return is_template(e.kind()) || e.kind() == cpp_entity_kind::template_template_parameter_t; 76 | } 77 | 78 | cpp_entity_kind cpp_template_template_parameter::kind() noexcept 79 | { 80 | return cpp_entity_kind::template_template_parameter_t; 81 | } 82 | 83 | cpp_entity_kind cpp_template_template_parameter::do_get_entity_kind() const noexcept 84 | { 85 | return kind(); 86 | } 87 | -------------------------------------------------------------------------------- /src/cpp_type_alias.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_type_alias::kind() noexcept 11 | { 12 | return cpp_entity_kind::type_alias_t; 13 | } 14 | 15 | std::unique_ptr cpp_type_alias::build(const cpp_entity_index& idx, cpp_entity_id id, 16 | std::string name, 17 | std::unique_ptr type) 18 | { 19 | auto result = build(std::move(name), std::move(type)); 20 | idx.register_forward_declaration(std::move(id), type_safe::cref(*result)); // not a definition 21 | return result; 22 | } 23 | 24 | std::unique_ptr cpp_type_alias::build(std::string name, 25 | std::unique_ptr type) 26 | { 27 | return std::unique_ptr(new cpp_type_alias(std::move(name), std::move(type))); 28 | } 29 | 30 | cpp_entity_kind cpp_type_alias::do_get_entity_kind() const noexcept 31 | { 32 | return kind(); 33 | } 34 | -------------------------------------------------------------------------------- /src/cpp_variable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_variable::kind() noexcept 11 | { 12 | return cpp_entity_kind::variable_t; 13 | } 14 | 15 | std::unique_ptr cpp_variable::build( 16 | const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, 17 | std::unique_ptr def, cpp_storage_class_specifiers spec, bool is_constexpr, 18 | type_safe::optional semantic_parent) 19 | { 20 | auto result = std::unique_ptr( 21 | new cpp_variable(std::move(name), std::move(type), std::move(def), spec, is_constexpr)); 22 | result->set_semantic_parent(std::move(semantic_parent)); 23 | idx.register_definition(std::move(id), type_safe::cref(*result)); 24 | return result; 25 | } 26 | 27 | std::unique_ptr cpp_variable::build_declaration( 28 | cpp_entity_id definition_id, std::string name, std::unique_ptr type, 29 | cpp_storage_class_specifiers spec, bool is_constexpr, 30 | type_safe::optional semantic_parent) 31 | { 32 | auto result = std::unique_ptr( 33 | new cpp_variable(std::move(name), std::move(type), nullptr, spec, is_constexpr)); 34 | result->set_semantic_parent(std::move(semantic_parent)); 35 | result->mark_declaration(definition_id); 36 | return result; 37 | } 38 | 39 | cpp_entity_kind cpp_variable::do_get_entity_kind() const noexcept 40 | { 41 | return kind(); 42 | } 43 | -------------------------------------------------------------------------------- /src/cpp_variable_template.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | cpp_entity_kind cpp_variable_template::kind() noexcept 11 | { 12 | return cpp_entity_kind::variable_template_t; 13 | } 14 | 15 | cpp_entity_kind cpp_variable_template::do_get_entity_kind() const noexcept 16 | { 17 | return kind(); 18 | } 19 | -------------------------------------------------------------------------------- /src/diagnostic_logger.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | using namespace cppast; 10 | 11 | bool diagnostic_logger::log(const char* source, const diagnostic& d) const 12 | { 13 | if (!verbose_ && d.severity == severity::debug) 14 | return false; 15 | return do_log(source, d); 16 | } 17 | 18 | type_safe::object_ref cppast::default_logger() noexcept 19 | { 20 | static const stderr_diagnostic_logger logger(false); 21 | return type_safe::ref(logger); 22 | } 23 | 24 | type_safe::object_ref cppast::default_verbose_logger() noexcept 25 | { 26 | static const stderr_diagnostic_logger logger(true); 27 | return type_safe::ref(logger); 28 | } 29 | 30 | bool stderr_diagnostic_logger::do_log(const char* source, const diagnostic& d) const 31 | { 32 | auto loc = d.location.to_string(); 33 | if (loc.empty()) 34 | std::fprintf(stderr, "[%s] [%s] %s\n", source, to_string(d.severity), d.message.c_str()); 35 | else 36 | std::fprintf(stderr, "[%s] [%s] %s %s\n", source, to_string(d.severity), 37 | d.location.to_string().c_str(), d.message.c_str()); 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /src/libclang/concept_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "libclang_visitor.hpp" 9 | #include "parse_functions.hpp" 10 | 11 | using namespace cppast; 12 | 13 | std::unique_ptr detail::try_parse_cpp_concept(const detail::parse_context& context, 14 | const CXCursor& cur) 15 | { 16 | DEBUG_ASSERT(cur.kind == CXCursor_UnexposedDecl || cur.kind == CXCursor_ConceptDecl, 17 | detail::assert_handler{}); 18 | if (libclang_definitely_has_concept_support && cur.kind != CXCursor_ConceptDecl) 19 | return nullptr; 20 | 21 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 22 | detail::cxtoken_stream stream(tokenizer, cur); 23 | 24 | if (!detail::skip_if(stream, "template")) 25 | return nullptr; 26 | 27 | if (stream.peek() != "<") 28 | return nullptr; 29 | 30 | auto closing_bracket = detail::find_closing_bracket(stream); 31 | auto params = to_string(stream, closing_bracket.bracket, closing_bracket.unmunch); 32 | 33 | if (!detail::skip_if(stream, ">")) 34 | return nullptr; 35 | 36 | if (!detail::skip_if(stream, "concept")) 37 | return nullptr; 38 | 39 | const auto& identifier_token = stream.get(); 40 | DEBUG_ASSERT(identifier_token.kind() == CXTokenKind::CXToken_Identifier, 41 | detail::assert_handler{}); 42 | 43 | detail::skip(stream, "="); 44 | auto expr = parse_raw_expression(context, stream, stream.end() - 1, 45 | cpp_builtin_type::build(cpp_builtin_type_kind::cpp_bool)); 46 | 47 | cpp_concept::builder builder(identifier_token.value().std_str()); 48 | builder.set_expression(std::move(expr)); 49 | builder.set_parameters(std::move(params)); 50 | return builder.finish(*context.idx, detail::get_entity_id(cur)); 51 | } 52 | -------------------------------------------------------------------------------- /src/libclang/debug_helper.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include "debug_helper.hpp" 5 | 6 | #include 7 | #include 8 | 9 | #include "cxtokenizer.hpp" 10 | 11 | using namespace cppast; 12 | 13 | detail::cxstring detail::get_display_name(const CXCursor& cur) noexcept 14 | { 15 | return cxstring(clang_getCursorDisplayName(cur)); 16 | } 17 | 18 | detail::cxstring detail::get_cursor_kind_spelling(const CXCursor& cur) noexcept 19 | { 20 | return cxstring(clang_getCursorKindSpelling(clang_getCursorKind(cur))); 21 | } 22 | 23 | detail::cxstring detail::get_type_kind_spelling(const CXType& type) noexcept 24 | { 25 | return cxstring(clang_getTypeKindSpelling(type.kind)); 26 | } 27 | 28 | namespace 29 | { 30 | std::mutex mtx; 31 | } 32 | 33 | void detail::print_cursor_info(const CXCursor& cur) noexcept 34 | { 35 | std::lock_guard lock(mtx); 36 | std::fprintf(stderr, "[debug] cursor '%s' (%s): %s\n", get_display_name(cur).c_str(), 37 | cxstring(clang_getCursorKindSpelling(cur.kind)).c_str(), 38 | cxstring(clang_getCursorUSR(cur)).c_str()); 39 | } 40 | 41 | void detail::print_type_info(const CXType& type) noexcept 42 | { 43 | std::lock_guard lock(mtx); 44 | std::fprintf(stderr, "[debug] type '%s' (%s)\n", cxstring(clang_getTypeSpelling(type)).c_str(), 45 | get_type_kind_spelling(type).c_str()); 46 | } 47 | 48 | void detail::print_tokens(const CXTranslationUnit& tu, const CXFile& file, 49 | const CXCursor& cur) noexcept 50 | { 51 | std::lock_guard lock(mtx); 52 | detail::cxtokenizer tokenizer(tu, file, cur); 53 | for (auto& token : tokenizer) 54 | std::fprintf(stderr, "%s ", token.c_str()); 55 | std::fputs("\n", stderr); 56 | } 57 | -------------------------------------------------------------------------------- /src/libclang/debug_helper.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_DEBUG_HELPER_HPP_INCLUDED 5 | #define CPPAST_DEBUG_HELPER_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include "raii_wrapper.hpp" 10 | 11 | namespace cppast 12 | { 13 | namespace detail 14 | { 15 | cxstring get_display_name(const CXCursor& cur) noexcept; 16 | 17 | cxstring get_cursor_kind_spelling(const CXCursor& cur) noexcept; 18 | 19 | cxstring get_type_kind_spelling(const CXType& type) noexcept; 20 | 21 | void print_cursor_info(const CXCursor& cur) noexcept; 22 | 23 | void print_type_info(const CXType& type) noexcept; 24 | 25 | void print_tokens(const CXTranslationUnit& tu, const CXFile& file, 26 | const CXCursor& cur) noexcept; 27 | } // namespace detail 28 | } // namespace cppast 29 | 30 | #endif // CPPAST_DEBUG_HELPER_HPP_INCLUDED 31 | -------------------------------------------------------------------------------- /src/libclang/enum_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include "libclang_visitor.hpp" 7 | #include "parse_functions.hpp" 8 | 9 | using namespace cppast; 10 | 11 | namespace 12 | { 13 | std::unique_ptr parse_enum_value(const detail::parse_context& context, 14 | const CXCursor& cur) 15 | { 16 | if (clang_isAttribute(clang_getCursorKind(cur))) 17 | return nullptr; 18 | 19 | DEBUG_ASSERT(cur.kind == CXCursor_EnumConstantDecl, detail::parse_error_handler{}, cur, 20 | "unexpected child cursor of enum"); 21 | 22 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 23 | detail::cxtoken_stream stream(tokenizer, cur); 24 | 25 | // [], 26 | // or: [] = , 27 | auto& name = stream.get().value(); 28 | auto attributes = detail::parse_attributes(stream); 29 | 30 | std::unique_ptr value; 31 | if (detail::skip_if(stream, "=")) 32 | { 33 | detail::visit_children(cur, [&](const CXCursor& child) { 34 | DEBUG_ASSERT(clang_isExpression(child.kind) && !value, detail::parse_error_handler{}, 35 | cur, "unexpected child cursor of enum value"); 36 | 37 | value = detail::parse_expression(context, child); 38 | }); 39 | } 40 | 41 | auto result = cpp_enum_value::build(*context.idx, detail::get_entity_id(cur), name.c_str(), 42 | std::move(value)); 43 | result->add_attribute(attributes); 44 | return result; 45 | } 46 | 47 | cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur, 48 | type_safe::optional& semantic_parent) 49 | { 50 | auto name = detail::get_cursor_name(cur); 51 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 52 | detail::cxtoken_stream stream(tokenizer, cur); 53 | 54 | // enum [class/struct] [] name [: type] { 55 | detail::skip(stream, "enum"); 56 | auto scoped = detail::skip_if(stream, "class") || detail::skip_if(stream, "struct"); 57 | auto attributes = detail::parse_attributes(stream); 58 | 59 | std::string scope; 60 | while (!detail::skip_if(stream, name.c_str())) 61 | if (!detail::append_scope(stream, scope)) 62 | DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur, "unexpected tokens in enum name"); 63 | if (!scope.empty()) 64 | semantic_parent = cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)), 65 | std::move(scope)); 66 | 67 | // parse type 68 | auto type = detail::parse_type(context, cur, clang_getEnumDeclIntegerType(cur)); 69 | auto type_given = detail::skip_if(stream, ":"); 70 | 71 | auto result = cpp_enum::builder(name.c_str(), scoped, std::move(type), type_given); 72 | result.get().add_attribute(attributes); 73 | return result; 74 | } 75 | } // namespace 76 | 77 | std::unique_ptr detail::parse_cpp_enum(const detail::parse_context& context, 78 | const CXCursor& cur) 79 | { 80 | DEBUG_ASSERT(cur.kind == CXCursor_EnumDecl, detail::assert_handler{}); 81 | 82 | type_safe::optional semantic_parent; 83 | auto builder = make_enum_builder(context, cur, semantic_parent); 84 | context.comments.match(builder.get(), cur); 85 | detail::visit_children(cur, [&](const CXCursor& child) { 86 | try 87 | { 88 | auto entity = parse_enum_value(context, child); 89 | if (entity) 90 | { 91 | context.comments.match(*entity, child); 92 | builder.add_value(std::move(entity)); 93 | } 94 | } 95 | catch (parse_error& ex) 96 | { 97 | context.error = true; 98 | context.logger->log("libclang parser", ex.get_diagnostic(context.file)); 99 | } 100 | catch (std::logic_error& ex) 101 | { 102 | context.error = true; 103 | auto location = make_location(child); 104 | context.logger->log("libclang parser", 105 | diagnostic{ex.what(), location, severity::error}); 106 | } 107 | }); 108 | if (clang_isCursorDefinition(cur)) 109 | return builder.finish(*context.idx, get_entity_id(cur), std::move(semantic_parent)); 110 | else 111 | return builder.finish_declaration(*context.idx, get_entity_id(cur)); 112 | } 113 | -------------------------------------------------------------------------------- /src/libclang/expression_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include "parse_functions.hpp" 7 | 8 | using namespace cppast; 9 | 10 | std::unique_ptr detail::parse_expression(const detail::parse_context& context, 11 | const CXCursor& cur) 12 | { 13 | auto kind = clang_getCursorKind(cur); 14 | DEBUG_ASSERT(clang_isExpression(kind), detail::assert_handler{}); 15 | 16 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 17 | detail::cxtoken_stream stream(tokenizer, cur); 18 | 19 | auto type = parse_type(context, cur, clang_getCursorType(cur)); 20 | auto expr = to_string(stream, stream.end(), false); 21 | if (kind == CXCursor_CallExpr && (expr.empty() || expr.back().spelling != ")")) 22 | { 23 | // we have a call expression that doesn't end in a closing parentheses 24 | // this means default constructor, don't parse it at all 25 | // so, for example a variable doesn't have a default value 26 | return nullptr; 27 | } 28 | else if (kind == CXCursor_CharacterLiteral || kind == CXCursor_CompoundLiteralExpr 29 | || kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral 30 | || kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral 31 | || kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr) 32 | return cpp_literal_expression::build(std::move(type), expr.as_string()); 33 | else 34 | return cpp_unexposed_expression::build(std::move(type), std::move(expr)); 35 | } 36 | 37 | std::unique_ptr detail::parse_raw_expression(const parse_context&, 38 | cxtoken_stream& stream, 39 | cxtoken_iterator end, 40 | std::unique_ptr type) 41 | { 42 | if (stream.done()) 43 | return nullptr; 44 | 45 | auto expr = to_string(stream, std::prev(end)->value() == ";" ? std::prev(end) : end, false); 46 | return cpp_unexposed_expression::build(std::move(type), std::move(expr)); 47 | } 48 | -------------------------------------------------------------------------------- /src/libclang/friend_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "libclang_visitor.hpp" 10 | #include "parse_functions.hpp" 11 | 12 | using namespace cppast; 13 | 14 | std::unique_ptr detail::parse_cpp_friend(const detail::parse_context& context, 15 | const CXCursor& cur) 16 | { 17 | DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_FriendDecl, detail::assert_handler{}); 18 | 19 | std::string comment; 20 | std::unique_ptr entity; 21 | std::unique_ptr type; 22 | std::string namespace_str; 23 | type_safe::optional inst_builder; 24 | detail::visit_children(cur, [&](const CXCursor& child) { 25 | auto kind = clang_getCursorKind(child); 26 | if (kind == CXCursor_TypeRef) 27 | { 28 | auto referenced = clang_getCursorReferenced(child); 29 | if (inst_builder) 30 | { 31 | namespace_str.clear(); 32 | inst_builder.value().add_argument( 33 | detail::parse_type(context, referenced, clang_getCursorType(referenced))); 34 | } 35 | else if (clang_getCursorKind(referenced) == CXCursor_TemplateTypeParameter) 36 | // parse template parameter type 37 | type = cpp_template_parameter_type::build( 38 | cpp_template_type_parameter_ref(detail::get_entity_id(referenced), 39 | detail::get_cursor_name(child).c_str())); 40 | else if (!namespace_str.empty()) 41 | { 42 | // parse as user defined type 43 | // we can't use the other branch here, 44 | // as then the class name would be wrong 45 | auto name = detail::get_cursor_name(referenced); 46 | type = cpp_user_defined_type::build( 47 | cpp_type_ref(detail::get_entity_id(referenced), 48 | namespace_str + "::" + name.c_str())); 49 | } 50 | else 51 | { 52 | // for some reason libclang gives a type ref here 53 | // we actually need a class decl cursor, so parse the referenced one 54 | // this might be a definition, so give friend information to the parser 55 | entity = parse_entity(context, nullptr, referenced, cur); 56 | comment = type_safe::copy(entity->comment()).value_or(""); 57 | } 58 | } 59 | else if (kind == CXCursor_NamespaceRef) 60 | namespace_str += detail::get_cursor_name(child).c_str(); 61 | else if (kind == CXCursor_TemplateRef) 62 | { 63 | if (!namespace_str.empty()) 64 | namespace_str += "::"; 65 | auto templ = cpp_template_ref(detail::get_entity_id(clang_getCursorReferenced(child)), 66 | namespace_str + detail::get_cursor_name(child).c_str()); 67 | namespace_str.clear(); 68 | if (!inst_builder) 69 | inst_builder = cpp_template_instantiation_type::builder(std::move(templ)); 70 | else 71 | inst_builder.value().add_argument(std::move(templ)); 72 | } 73 | else if (clang_isDeclaration(kind)) 74 | { 75 | entity = parse_entity(context, nullptr, child, cur); 76 | if (entity) 77 | { 78 | // steal comment 79 | comment = type_safe::copy(entity->comment()).value_or(""); 80 | entity->set_comment(type_safe::nullopt); 81 | } 82 | } 83 | else if (inst_builder && clang_isExpression(kind)) 84 | { 85 | namespace_str.clear(); 86 | inst_builder.value().add_argument(detail::parse_expression(context, child)); 87 | } 88 | }); 89 | 90 | std::unique_ptr result; 91 | if (entity) 92 | result = cpp_friend::build(std::move(entity)); 93 | else if (type) 94 | result = cpp_friend::build(std::move(type)); 95 | else if (inst_builder) 96 | result = cpp_friend::build(inst_builder.value().finish()); 97 | else 98 | DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur, 99 | "unknown child entity of friend declaration"); 100 | if (!comment.empty()) 101 | // set comment of entity... 102 | result->set_comment(std::move(comment)); 103 | // ... but override if this finds a different comment 104 | // due to clang_getCursorReferenced(), this may happen 105 | context.comments.match(*result, cur); 106 | return result; 107 | } 108 | -------------------------------------------------------------------------------- /src/libclang/language_linkage_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include "parse_functions.hpp" 5 | 6 | #include 7 | #include 8 | 9 | #include "libclang_visitor.hpp" 10 | 11 | using namespace cppast; 12 | 13 | std::unique_ptr detail::try_parse_cpp_language_linkage(const parse_context& context, 14 | const CXCursor& cur) 15 | { 16 | DEBUG_ASSERT(cur.kind == CXCursor_UnexposedDecl, 17 | detail::assert_handler{}); // not exposed currently 18 | 19 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 20 | detail::cxtoken_stream stream(tokenizer, cur); 21 | 22 | // extern ... 23 | if (!detail::skip_if(stream, "extern")) 24 | return nullptr; 25 | // unexposed variable starting with extern - must be a language linkage 26 | // (function, variables are not unexposed) 27 | auto& name = stream.get().value(); 28 | 29 | auto builder = cpp_language_linkage::builder(name.c_str()); 30 | context.comments.match(builder.get(), cur); 31 | detail::visit_children(cur, [&](const CXCursor& child) { 32 | auto entity = parse_entity(context, &builder.get(), child); 33 | if (entity) 34 | builder.add_child(std::move(entity)); 35 | }); 36 | 37 | return builder.finish(); 38 | } 39 | -------------------------------------------------------------------------------- /src/libclang/libclang_visitor.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED 5 | #define CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include "raii_wrapper.hpp" 10 | 11 | namespace cppast 12 | { 13 | namespace detail 14 | { 15 | // visits direct children of an entity 16 | template 17 | void visit_children(CXCursor parent, Func f, bool recurse = false) 18 | { 19 | auto continue_lambda = [](CXCursor cur, CXCursor, CXClientData data) { 20 | auto& actual_cb = *static_cast(data); 21 | actual_cb(cur); 22 | return CXChildVisit_Continue; 23 | }; 24 | auto recurse_lambda = [](CXCursor cur, CXCursor, CXClientData data) { 25 | auto& actual_cb = *static_cast(data); 26 | actual_cb(cur); 27 | return CXChildVisit_Recurse; 28 | }; 29 | 30 | if (recurse) 31 | clang_visitChildren(parent, recurse_lambda, &f); 32 | else 33 | clang_visitChildren(parent, continue_lambda, &f); 34 | } 35 | 36 | // visits a translation unit 37 | // notes: only visits if directly defined in file, not included 38 | template 39 | void visit_tu(const cxtranslation_unit& tu, const char* path, Func f) 40 | { 41 | auto in_tu = [&](const CXCursor& cur) { 42 | auto location = clang_getCursorLocation(cur); 43 | 44 | CXString cx_file_name; 45 | clang_getPresumedLocation(location, &cx_file_name, nullptr, nullptr); 46 | cxstring file_name(cx_file_name); 47 | 48 | return file_name == path; 49 | }; 50 | 51 | visit_children(clang_getTranslationUnitCursor(tu.get()), [&](const CXCursor& cur) { 52 | if (in_tu(cur)) 53 | f(cur); 54 | }); 55 | } 56 | } // namespace detail 57 | } // namespace cppast 58 | 59 | #endif // CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED 60 | -------------------------------------------------------------------------------- /src/libclang/parse_error.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_PARSE_ERROR_HPP_INCLUDED 5 | #define CPPAST_PARSE_ERROR_HPP_INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "debug_helper.hpp" 13 | 14 | namespace cppast 15 | { 16 | namespace detail 17 | { 18 | inline source_location make_location(const CXCursor& cur) 19 | { 20 | auto loc = clang_getCursorLocation(cur); 21 | 22 | CXString file; 23 | unsigned line; 24 | clang_getPresumedLocation(loc, &file, &line, nullptr); 25 | 26 | return source_location::make_file(cxstring(file).c_str(), line); 27 | } 28 | 29 | inline source_location make_location(const CXFile& file, const CXCursor& cur) 30 | { 31 | return source_location::make_entity(get_display_name(cur).c_str(), 32 | cxstring(clang_getFileName(file)).c_str()); 33 | } 34 | 35 | inline source_location make_location(const CXType& type) 36 | { 37 | return source_location::make_entity(cxstring(clang_getTypeSpelling(type)).c_str()); 38 | } 39 | 40 | // thrown on a parsing error 41 | // not meant to escape to the user 42 | class parse_error : public std::logic_error 43 | { 44 | public: 45 | parse_error(source_location loc, std::string message) 46 | : std::logic_error(std::move(message)), location_(std::move(loc)) 47 | {} 48 | 49 | parse_error(const CXCursor& cur, std::string message) 50 | : parse_error(make_location(cur), std::move(message)) 51 | {} 52 | 53 | parse_error(const CXType& type, std::string message) 54 | : parse_error(make_location(type), std::move(message)) 55 | {} 56 | 57 | diagnostic get_diagnostic(const CXFile& file) 58 | { 59 | return get_diagnostic(cxstring(clang_getFileName(file)).c_str()); 60 | } 61 | 62 | diagnostic get_diagnostic(std::string file) 63 | { 64 | location_.file = std::move(file); 65 | return diagnostic{what(), location_, severity::error}; 66 | } 67 | 68 | private: 69 | source_location location_; 70 | }; 71 | 72 | // DEBUG_ASSERT handler for parse errors 73 | // throws a parse_error exception 74 | struct parse_error_handler : debug_assert::set_level<1>, debug_assert::allow_exception 75 | { 76 | static void handle(const debug_assert::source_location&, const char*, const CXCursor& cur, 77 | std::string message) 78 | { 79 | throw parse_error(cur, std::move(message)); 80 | } 81 | 82 | static void handle(const debug_assert::source_location&, const char*, const CXType& type, 83 | std::string message) 84 | { 85 | throw parse_error(type, std::move(message)); 86 | } 87 | }; 88 | } // namespace detail 89 | } // namespace cppast 90 | 91 | #endif // CPPAST_PARSE_ERROR_HPP_INCLUDED 92 | -------------------------------------------------------------------------------- /src/libclang/preprocessor.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_PREPROCESSOR_HPP_INCLUDED 5 | #define CPPAST_PREPROCESSOR_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | namespace cppast 11 | { 12 | namespace detail 13 | { 14 | struct pp_macro 15 | { 16 | std::unique_ptr macro; 17 | unsigned line; 18 | }; 19 | 20 | struct pp_include 21 | { 22 | std::string file_name, full_path; 23 | cpp_include_kind kind; 24 | unsigned line; 25 | }; 26 | 27 | struct pp_doc_comment 28 | { 29 | std::string comment; 30 | unsigned line; 31 | enum 32 | { 33 | c, 34 | cpp, 35 | end_of_line, 36 | } kind; 37 | 38 | bool matches(const cpp_entity& e, unsigned line); 39 | }; 40 | 41 | struct preprocessor_output 42 | { 43 | std::string source; 44 | std::vector includes; 45 | std::vector macros; 46 | std::vector comments; 47 | }; 48 | 49 | preprocessor_output preprocess(const libclang_compile_config& config, const char* path, 50 | const diagnostic_logger& logger); 51 | } // namespace detail 52 | } // namespace cppast 53 | 54 | #endif // CPPAST_PREPROCESSOR_HPP_INCLUDED 55 | -------------------------------------------------------------------------------- /src/libclang/raii_wrapper.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #ifndef CPPAST_RAII_WRAPPER_HPP_INCLUDED 5 | #define CPPAST_RAII_WRAPPER_HPP_INCLUDED 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace cppast 17 | { 18 | namespace detail 19 | { 20 | template 21 | class raii_wrapper : Deleter 22 | { 23 | static_assert(std::is_pointer::value, ""); 24 | 25 | public: 26 | raii_wrapper() noexcept : obj_(nullptr) {} 27 | 28 | explicit raii_wrapper(T obj) noexcept : obj_(obj) 29 | { 30 | DEBUG_ASSERT(obj_, detail::assert_handler{}); 31 | } 32 | 33 | raii_wrapper(raii_wrapper&& other) noexcept : obj_(other.obj_) 34 | { 35 | DEBUG_ASSERT(obj_, detail::assert_handler{}); 36 | other.obj_ = nullptr; 37 | } 38 | 39 | ~raii_wrapper() noexcept 40 | { 41 | if (obj_) 42 | static_cast(*this)(obj_); 43 | } 44 | 45 | raii_wrapper& operator=(raii_wrapper&& other) noexcept 46 | { 47 | raii_wrapper tmp(std::move(other)); 48 | swap(*this, tmp); 49 | return *this; 50 | } 51 | 52 | friend void swap(raii_wrapper& a, raii_wrapper& b) noexcept 53 | { 54 | std::swap(a.obj_, b.obj_); 55 | } 56 | 57 | T get() const noexcept 58 | { 59 | DEBUG_ASSERT(obj_, detail::assert_handler{}); 60 | return obj_; 61 | } 62 | 63 | private: 64 | T obj_; 65 | }; 66 | 67 | struct cxindex_deleter 68 | { 69 | void operator()(CXIndex idx) noexcept 70 | { 71 | clang_disposeIndex(idx); 72 | } 73 | }; 74 | 75 | using cxindex = raii_wrapper; 76 | 77 | struct cxtranslation_unit_deleter 78 | { 79 | void operator()(CXTranslationUnit unit) noexcept 80 | { 81 | clang_disposeTranslationUnit(unit); 82 | } 83 | }; 84 | 85 | using cxtranslation_unit = raii_wrapper; 86 | 87 | class cxstring 88 | { 89 | public: 90 | explicit cxstring(CXString str) noexcept : str_(string(str)) {} 91 | 92 | cxstring(cxstring&& other) noexcept : str_(other.str_) 93 | { 94 | other.str_.reset(); 95 | } 96 | 97 | cxstring& operator=(cxstring&& other) noexcept 98 | { 99 | if (str_) 100 | clang_disposeString(str_.value().str); 101 | str_ = other.str_; 102 | other.str_.reset(); 103 | return *this; 104 | } 105 | 106 | ~cxstring() noexcept 107 | { 108 | if (str_) 109 | clang_disposeString(str_.value().str); 110 | } 111 | 112 | const char* c_str() const noexcept 113 | { 114 | return str_ ? str_.value().c_str : ""; 115 | } 116 | 117 | std::string std_str() const noexcept 118 | { 119 | return c_str(); 120 | } 121 | 122 | char operator[](std::size_t i) const noexcept 123 | { 124 | return c_str()[i]; 125 | } 126 | 127 | std::size_t length() const noexcept 128 | { 129 | return str_ ? str_.value().length : 0u; 130 | } 131 | 132 | bool empty() const noexcept 133 | { 134 | return length() == 0u; 135 | } 136 | 137 | private: 138 | struct string 139 | { 140 | CXString str; 141 | const char* c_str; 142 | std::size_t length; 143 | 144 | explicit string(CXString str) 145 | : str(std::move(str)), c_str(clang_getCString(str)), length(std::strlen(c_str)) 146 | {} 147 | }; 148 | type_safe::optional str_; 149 | }; 150 | 151 | inline bool operator==(const cxstring& a, const cxstring& b) noexcept 152 | { 153 | return std::strcmp(a.c_str(), b.c_str()) == 0; 154 | } 155 | 156 | inline bool operator==(const cxstring& a, const char* str) noexcept 157 | { 158 | return std::strcmp(a.c_str(), str) == 0; 159 | } 160 | 161 | inline bool operator==(const char* str, const cxstring& b) noexcept 162 | { 163 | return std::strcmp(str, b.c_str()) == 0; 164 | } 165 | 166 | inline bool operator!=(const cxstring& a, const cxstring& b) noexcept 167 | { 168 | return !(a == b); 169 | } 170 | 171 | inline bool operator!=(const cxstring& a, const char* str) noexcept 172 | { 173 | return !(a == str); 174 | } 175 | 176 | inline bool operator!=(const char* str, const cxstring& b) noexcept 177 | { 178 | return !(str == b); 179 | } 180 | } // namespace detail 181 | } // namespace cppast 182 | 183 | #endif // CPPAST_RAII_WRAPPER_HPP_INCLUDED 184 | -------------------------------------------------------------------------------- /src/libclang/variable_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include "parse_functions.hpp" 5 | 6 | #include 7 | #include 8 | 9 | #include "libclang_visitor.hpp" 10 | 11 | using namespace cppast; 12 | 13 | std::unique_ptr detail::parse_default_value(cpp_attribute_list& attributes, 14 | const detail::parse_context& context, 15 | const CXCursor& cur, const char* name) 16 | { 17 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 18 | detail::cxtoken_stream stream(tokenizer, cur); 19 | 20 | auto has_default = false; 21 | auto got_name = *name == '\0'; 22 | for (auto paren_count = 0; !stream.done();) 23 | { 24 | if (detail::skip_if(stream, "(")) 25 | ++paren_count; 26 | else if (detail::skip_if(stream, ")")) 27 | --paren_count; 28 | else if (!got_name && detail::skip_if(stream, name)) 29 | got_name = true; 30 | else if (paren_count == 0 && got_name && detail::skip_if(stream, "=")) 31 | { 32 | // heuristic: we're outside of parens, the name was already encountered 33 | // and we have an equal sign -> treat this as default value 34 | // (yes this breaks for evil types) 35 | has_default = true; 36 | break; 37 | } 38 | else 39 | { 40 | auto cur_attributes = detail::parse_attributes(stream, true); 41 | attributes.insert(attributes.end(), cur_attributes.begin(), cur_attributes.end()); 42 | } 43 | } 44 | if (has_default) 45 | return parse_raw_expression(context, stream, stream.end(), 46 | parse_type(context, cur, clang_getCursorType(cur))); 47 | else 48 | return nullptr; 49 | } 50 | 51 | std::unique_ptr detail::parse_cpp_variable(const detail::parse_context& context, 52 | const CXCursor& cur) 53 | { 54 | DEBUG_ASSERT(cur.kind == CXCursor_VarDecl, detail::assert_handler{}); 55 | 56 | auto name = get_cursor_name(cur); 57 | auto type = parse_type(context, cur, clang_getCursorType(cur)); 58 | auto storage_class = get_storage_class(cur); 59 | auto is_constexpr = false; 60 | 61 | // just look for thread local or constexpr 62 | // can't appear anywhere else, so good enough 63 | detail::cxtokenizer tokenizer(context.tu, context.file, cur); 64 | for (auto& token : tokenizer) 65 | if (token.value() == "thread_local") 66 | storage_class 67 | = cpp_storage_class_specifiers(storage_class | cpp_storage_class_thread_local); 68 | else if (token.value() == "constexpr") 69 | is_constexpr = true; 70 | 71 | cpp_attribute_list attributes; 72 | auto default_value = parse_default_value(attributes, context, cur, name.c_str()); 73 | 74 | auto parent = get_semantic_parent(cur, false); 75 | 76 | std::unique_ptr result; 77 | if (clang_isCursorDefinition(cur)) 78 | { 79 | result = cpp_variable::build(*context.idx, get_entity_id(cur), name.c_str(), 80 | std::move(type), std::move(default_value), storage_class, 81 | is_constexpr, std::move(parent)); 82 | } 83 | else 84 | { 85 | result = cpp_variable::build_declaration(get_entity_id(cur), name.c_str(), std::move(type), 86 | storage_class, is_constexpr, std::move(parent)); 87 | } 88 | context.comments.match(*result, cur); 89 | result->add_attribute(attributes); 90 | return result; 91 | } 92 | 93 | std::unique_ptr detail::parse_cpp_member_variable(const detail::parse_context& context, 94 | const CXCursor& cur) 95 | { 96 | DEBUG_ASSERT(cur.kind == CXCursor_FieldDecl, detail::assert_handler{}); 97 | 98 | auto name = get_cursor_name(cur); 99 | auto type = parse_type(context, cur, clang_getCursorType(cur)); 100 | auto is_mutable = clang_CXXField_isMutable(cur) != 0u; 101 | 102 | cpp_attribute_list attributes; 103 | auto default_value = parse_default_value(attributes, context, cur, name.c_str()); 104 | 105 | std::unique_ptr result; 106 | if (clang_Cursor_isBitField(cur)) 107 | { 108 | auto no_bits = clang_getFieldDeclBitWidth(cur); 109 | DEBUG_ASSERT(no_bits >= 0, detail::parse_error_handler{}, cur, "invalid number of bits"); 110 | if (name.empty()) 111 | result = cpp_bitfield::build(std::move(type), unsigned(no_bits), is_mutable); 112 | else 113 | result = cpp_bitfield::build(*context.idx, get_entity_id(cur), name.c_str(), 114 | std::move(type), unsigned(no_bits), is_mutable); 115 | } 116 | else 117 | { 118 | result = cpp_member_variable::build(*context.idx, get_entity_id(cur), name.c_str(), 119 | std::move(type), std::move(default_value), is_mutable); 120 | } 121 | result->add_attribute(attributes); 122 | context.comments.match(*result, cur); 123 | return result; 124 | } 125 | -------------------------------------------------------------------------------- /src/visitor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace cppast; 17 | 18 | namespace 19 | { 20 | cpp_access_specifier_kind get_initial_access(const cpp_entity& e) 21 | { 22 | if (e.kind() == cpp_class::kind()) 23 | return static_cast(e).class_kind() == cpp_class_kind::class_t 24 | ? cpp_private 25 | : cpp_public; 26 | return cpp_public; 27 | } 28 | 29 | void update_access(cpp_access_specifier_kind& child_access, const cpp_entity& child) 30 | { 31 | if (child.kind() == cpp_access_specifier::kind()) 32 | child_access = static_cast(child).access_specifier(); 33 | } 34 | 35 | template 36 | bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor, 37 | cpp_access_specifier_kind cur_access, bool last_child) 38 | { 39 | auto& container = static_cast(e); 40 | 41 | auto handle_children 42 | = cb(functor, container, {visitor_info::container_entity_enter, cur_access, last_child}); 43 | if (handle_children) 44 | { 45 | auto child_access = get_initial_access(e); 46 | for (auto iter = container.begin(); iter != container.end();) 47 | { 48 | auto& cur = *iter; 49 | ++iter; 50 | 51 | update_access(child_access, cur); 52 | 53 | if (!detail::visit(cur, cb, functor, child_access, iter == container.end())) 54 | return false; 55 | } 56 | } 57 | 58 | return cb(functor, container, {visitor_info::container_entity_exit, cur_access, last_child}); 59 | } 60 | } // namespace 61 | 62 | bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor, 63 | cpp_access_specifier_kind cur_access, bool last_child) 64 | { 65 | switch (e.kind()) 66 | { 67 | case cpp_entity_kind::file_t: 68 | return handle_container(e, cb, functor, cur_access, last_child); 69 | case cpp_entity_kind::language_linkage_t: 70 | return handle_container(e, cb, functor, cur_access, last_child); 71 | case cpp_entity_kind::namespace_t: 72 | return handle_container(e, cb, functor, cur_access, last_child); 73 | case cpp_entity_kind::enum_t: 74 | return handle_container(e, cb, functor, cur_access, last_child); 75 | case cpp_entity_kind::class_t: 76 | return handle_container(e, cb, functor, cur_access, last_child); 77 | case cpp_entity_kind::alias_template_t: 78 | return handle_container(e, cb, functor, cur_access, last_child); 79 | case cpp_entity_kind::variable_template_t: 80 | return handle_container(e, cb, functor, cur_access, last_child); 81 | case cpp_entity_kind::function_template_t: 82 | return handle_container(e, cb, functor, cur_access, last_child); 83 | case cpp_entity_kind::function_template_specialization_t: 84 | return handle_container(e, cb, functor, cur_access, 85 | last_child); 86 | case cpp_entity_kind::class_template_t: 87 | return handle_container(e, cb, functor, cur_access, last_child); 88 | case cpp_entity_kind::class_template_specialization_t: 89 | return handle_container(e, cb, functor, cur_access, 90 | last_child); 91 | 92 | case cpp_entity_kind::macro_parameter_t: 93 | case cpp_entity_kind::macro_definition_t: 94 | case cpp_entity_kind::include_directive_t: 95 | case cpp_entity_kind::namespace_alias_t: 96 | case cpp_entity_kind::using_directive_t: 97 | case cpp_entity_kind::using_declaration_t: 98 | case cpp_entity_kind::type_alias_t: 99 | case cpp_entity_kind::enum_value_t: 100 | case cpp_entity_kind::access_specifier_t: 101 | case cpp_entity_kind::base_class_t: 102 | case cpp_entity_kind::variable_t: 103 | case cpp_entity_kind::member_variable_t: 104 | case cpp_entity_kind::bitfield_t: 105 | case cpp_entity_kind::function_parameter_t: 106 | case cpp_entity_kind::function_t: 107 | case cpp_entity_kind::member_function_t: 108 | case cpp_entity_kind::conversion_op_t: 109 | case cpp_entity_kind::constructor_t: 110 | case cpp_entity_kind::destructor_t: 111 | case cpp_entity_kind::friend_t: 112 | case cpp_entity_kind::template_type_parameter_t: 113 | case cpp_entity_kind::non_type_template_parameter_t: 114 | case cpp_entity_kind::template_template_parameter_t: 115 | case cpp_entity_kind::concept_t: 116 | case cpp_entity_kind::static_assert_t: 117 | case cpp_entity_kind::unexposed_t: 118 | return cb(functor, e, {visitor_info::leaf_entity, cur_access, last_child}); 119 | 120 | case cpp_entity_kind::count: 121 | break; 122 | } 123 | 124 | DEBUG_UNREACHABLE(detail::assert_handler{}); 125 | return true; 126 | } 127 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | # SPDX-License-Identifier: MIT 3 | # found in the top-level directory of this distribution. 4 | 5 | # Fetch catch. 6 | message(STATUS "Fetching catch") 7 | include(FetchContent) 8 | FetchContent_Declare(catch URL https://github.com/catchorg/Catch2/archive/refs/tags/v2.13.9.zip) 9 | FetchContent_MakeAvailable(catch) 10 | 11 | set(tests 12 | code_generator.cpp 13 | cpp_alias_template.cpp 14 | cpp_attribute.cpp 15 | cpp_class.cpp 16 | cpp_class_template.cpp 17 | cpp_concept.cpp 18 | cpp_enum.cpp 19 | cpp_friend.cpp 20 | cpp_function.cpp 21 | cpp_function_template.cpp 22 | cpp_language_linkage.cpp 23 | cpp_member_function.cpp 24 | cpp_member_variable.cpp 25 | cpp_namespace.cpp 26 | cpp_preprocessor.cpp 27 | cpp_static_assert.cpp 28 | cpp_template_parameter.cpp 29 | cpp_token.cpp 30 | cpp_type_alias.cpp 31 | cpp_variable.cpp 32 | integration.cpp 33 | libclang_parser.cpp 34 | parser.cpp 35 | preprocessor.cpp 36 | visitor.cpp) 37 | 38 | # generate list of source files for the self parsing test 39 | get_target_property(files cppast SOURCES) 40 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cppast_files.hpp "// list of cppast source file includes\n") 41 | foreach(file ${files}) 42 | file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/cppast_files.hpp "\"${CMAKE_CURRENT_SOURCE_DIR}/../src/${file}\",\n") 43 | endforeach() 44 | 45 | add_executable(cppast_test test.cpp test_parser.hpp ${tests}) 46 | target_include_directories(cppast_test PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../src ${CMAKE_CURRENT_BINARY_DIR}) 47 | target_link_libraries(cppast_test PUBLIC cppast Catch2) 48 | target_compile_definitions(cppast_test PUBLIC CPPAST_INTEGRATION_FILE="${CMAKE_CURRENT_SOURCE_DIR}/integration.cpp" 49 | CPPAST_COMPILE_COMMANDS="${CMAKE_BINARY_DIR}") 50 | 51 | add_test(NAME unit_test COMMAND cppast_test "~[integration]") 52 | add_test(NAME integration_test COMMAND cppast_test "[integration]") 53 | 54 | if(CPPAST_TEST_GCOV AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")) 55 | setup_target_for_coverage( 56 | DIRECTORY ${CMAKE_SOURCE_DIR} 57 | NAME cppast_coverage 58 | SOURCES src/* include/* 59 | COLLECT_EXISTING 60 | ) 61 | target_link_libraries(cppast_test PRIVATE gcov) 62 | endif() 63 | -------------------------------------------------------------------------------- /test/cpp_concept.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/standardese/cppast/5329e377ab9b9ab9309e9641f3fcda04366a449a/test/cpp_concept.cpp -------------------------------------------------------------------------------- /test/cpp_language_linkage.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "test_parser.hpp" 9 | 10 | using namespace cppast; 11 | 12 | TEST_CASE("cpp_language_linkage") 13 | { 14 | auto code = R"( 15 | /// extern "C" enum a{ 16 | /// }; 17 | extern "C" enum a {}; 18 | 19 | enum b {}; 20 | 21 | /// extern "C++"{ 22 | /// enum c{ 23 | /// }; 24 | /// 25 | /// enum d{ 26 | /// }; 27 | /// 28 | /// enum e{ 29 | /// }; 30 | /// } 31 | extern "C++" // yup 32 | { 33 | enum c {}; 34 | enum d {}; 35 | enum e {}; 36 | } 37 | 38 | /// extern "C++"{ 39 | /// } 40 | extern "C++" {} 41 | 42 | enum f {}; 43 | )"; 44 | 45 | auto file = parse({}, "cpp_language_linkage.cpp", code); 46 | 47 | // check linkages 48 | auto count = test_visit(*file, [&](const cpp_language_linkage& linkage) { 49 | if (linkage.name() == "\"C\"") 50 | REQUIRE(!linkage.is_block()); 51 | else if (linkage.name() == "\"C++\"") 52 | REQUIRE(linkage.is_block()); 53 | else 54 | REQUIRE(false); 55 | }); 56 | REQUIRE(count == 3u); 57 | 58 | // check enums for their correct parent 59 | count = test_visit( 60 | *file, 61 | [&](const cpp_enum& e) { 62 | if (e.name() == "a") 63 | check_parent(e, "\"C\"", "a"); 64 | else if (e.name() == "b") 65 | check_parent(e, "cpp_language_linkage.cpp", "b"); 66 | else if (e.name() == "c") 67 | check_parent(e, "\"C++\"", "c"); 68 | else if (e.name() == "d") 69 | check_parent(e, "\"C++\"", "d"); 70 | else if (e.name() == "e") 71 | check_parent(e, "\"C++\"", "e"); 72 | else if (e.name() == "f") 73 | check_parent(e, "cpp_language_linkage.cpp", "f"); 74 | else 75 | REQUIRE(false); 76 | }, 77 | false); // don't check code generation here 78 | REQUIRE(count == 6u); 79 | } 80 | -------------------------------------------------------------------------------- /test/cpp_member_variable.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include "test_parser.hpp" 7 | 8 | using namespace cppast; 9 | 10 | TEST_CASE("cpp_member_variable") 11 | { 12 | auto code = R"( 13 | struct foo 14 | { 15 | /// int a; 16 | int a; 17 | /// float b=3.14f; 18 | float b = 3.14f; 19 | /// mutable char c; 20 | mutable char c; 21 | }; 22 | )"; 23 | 24 | cpp_entity_index idx; 25 | auto file = parse(idx, "cpp_member_variable.cpp", code); 26 | auto count = test_visit(*file, [&](const cpp_member_variable& var) { 27 | if (var.name() == "a") 28 | { 29 | auto type = cpp_builtin_type::build(cpp_int); 30 | REQUIRE(equal_types(idx, var.type(), *type)); 31 | REQUIRE(!var.default_value()); 32 | REQUIRE(!var.is_mutable()); 33 | } 34 | else if (var.name() == "b") 35 | { 36 | auto type = cpp_builtin_type::build(cpp_float); 37 | REQUIRE(equal_types(idx, var.type(), *type)); 38 | 39 | // all initializers are unexposed 40 | auto def = cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_float), 41 | cpp_token_string::tokenize("3.14f")); 42 | REQUIRE(var.default_value()); 43 | REQUIRE(equal_expressions(var.default_value().value(), *def)); 44 | 45 | REQUIRE(!var.is_mutable()); 46 | } 47 | else if (var.name() == "c") 48 | { 49 | auto type = cpp_builtin_type::build(cpp_char); 50 | REQUIRE(equal_types(idx, var.type(), *type)); 51 | REQUIRE(!var.default_value()); 52 | REQUIRE(var.is_mutable()); 53 | } 54 | else 55 | REQUIRE(false); 56 | }); 57 | REQUIRE(count == 3u); 58 | } 59 | 60 | TEST_CASE("cpp_bitfield") 61 | { 62 | auto code = R"( 63 | struct foo 64 | { 65 | /// char a:3; 66 | char a : 3; 67 | /// mutable char b:2; 68 | mutable char b : 2; 69 | /// char:0; 70 | char : 0; 71 | /// char c:3; 72 | char c : 3; 73 | /// char:4; 74 | char : 4; 75 | }; 76 | )"; 77 | 78 | auto file = parse({}, "cpp_bitfield.cpp", code); 79 | auto count = test_visit(*file, [&](const cpp_bitfield& bf) { 80 | REQUIRE(!bf.default_value()); 81 | REQUIRE(equal_types({}, bf.type(), *cpp_builtin_type::build(cpp_char))); 82 | 83 | if (bf.name() == "a") 84 | { 85 | REQUIRE(bf.no_bits() == 3u); 86 | REQUIRE(!bf.is_mutable()); 87 | } 88 | else if (bf.name() == "b") 89 | { 90 | REQUIRE(bf.no_bits() == 2u); 91 | REQUIRE(bf.is_mutable()); 92 | } 93 | else if (bf.name() == "c") 94 | { 95 | REQUIRE(bf.no_bits() == 3u); 96 | REQUIRE(!bf.is_mutable()); 97 | } 98 | else if (bf.name() == "") 99 | { 100 | REQUIRE(!bf.is_mutable()); 101 | if (bf.no_bits() != 0u && bf.no_bits() != 4u) 102 | { 103 | INFO(bf.no_bits()); 104 | REQUIRE(false); 105 | } 106 | } 107 | else 108 | REQUIRE(false); 109 | }); 110 | REQUIRE(count == 5u); 111 | } 112 | -------------------------------------------------------------------------------- /test/cpp_static_assert.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include "test_parser.hpp" 7 | 8 | using namespace cppast; 9 | 10 | TEST_CASE("cpp_static_assert") 11 | { 12 | auto code = R"( 13 | /// static_assert(true,""); 14 | static_assert(true, ""); 15 | /// static_assert(true||false,"a"); 16 | static_assert(true || false, "a"); 17 | 18 | template 19 | struct foo 20 | { 21 | /// static_assert(!B,"b"); 22 | static_assert(!B, "b"); 23 | }; 24 | )"; 25 | 26 | cpp_entity_index idx; 27 | auto file = parse(idx, "cpp_static_assert.cpp", code); 28 | auto count = test_visit(*file, [&](const cpp_static_assert& assert) { 29 | auto bool_t = cpp_builtin_type::build(cpp_builtin_type_kind::cpp_bool); 30 | 31 | REQUIRE(assert.name().empty()); 32 | if (assert.message() == "") 33 | REQUIRE(equal_expressions(assert.expression(), 34 | *cpp_literal_expression::build(std::move(bool_t), "true"))); 35 | else if (assert.message() == "a") 36 | REQUIRE(equal_expressions(assert.expression(), 37 | *cpp_unexposed_expression::build(std::move(bool_t), 38 | cpp_token_string::tokenize( 39 | "true||false")))); 40 | else if (assert.message() == "b") 41 | REQUIRE(equal_expressions(assert.expression(), 42 | *cpp_unexposed_expression::build(std::move(bool_t), 43 | cpp_token_string::tokenize( 44 | "!B")))); 45 | else 46 | REQUIRE(false); 47 | }); 48 | REQUIRE(count == 3u); 49 | } 50 | -------------------------------------------------------------------------------- /test/integration.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include "test_parser.hpp" 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | TEST_CASE("stdlib", "[!hide][integration]") 11 | { 12 | auto code = R"( 13 | // list of headers from: http://en.cppreference.com/w/cpp/header 14 | 15 | //#include -- problem with compiler built-in stuff on OSX 16 | #include 17 | //#include -- same as above 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | //#include -- something weird going on here 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | //#include -- missing types from C header (for some reason) 39 | #include 40 | 41 | //#include -- weird issue with compiler built-in stuff 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | //#include -- not supported on CI 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | #include 67 | 68 | #include 69 | 70 | //#include -- non-conforming GCC extension with regards to constexpr 71 | //#include -- weird double include issue under MSVC 72 | #include 73 | #include 74 | #include 75 | #include 76 | //#include -- same issue with cinttypes 77 | 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | 89 | #include 90 | //#include -- issue on OSX 91 | 92 | #include 93 | 94 | //#include -- issue on MSVC 95 | 96 | #include 97 | #include 98 | #include 99 | #include 100 | )"; 101 | write_file("stdlib.cpp", code); 102 | 103 | cpp_entity_index idx; 104 | simple_file_parser parser(type_safe::ref(idx), default_logger()); 105 | 106 | libclang_compile_config config; 107 | config.set_flags(cpp_standard::cpp_latest); 108 | auto file = parser.parse("stdlib.cpp", config); 109 | REQUIRE(!parser.error()); 110 | REQUIRE(file); 111 | 112 | REQUIRE(resolve_includes(parser, file.value(), config) == 61); 113 | REQUIRE(!parser.error()); 114 | } 115 | 116 | TEST_CASE("cppast", "[!hide][integration]") 117 | { 118 | const char* files[] = { 119 | #include 120 | }; 121 | 122 | cpp_entity_index idx; 123 | simple_file_parser parser(type_safe::ref(idx), default_logger()); 124 | 125 | libclang_compilation_database database(CPPAST_COMPILE_COMMANDS); 126 | libclang_compile_config config(database, CPPAST_INTEGRATION_FILE); 127 | config.set_flags(cpp_standard::cpp_latest); 128 | config.fast_preprocessing(true); 129 | parse_files(parser, files, config); 130 | 131 | REQUIRE(!parser.error()); 132 | } 133 | -------------------------------------------------------------------------------- /test/libclang_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | using namespace cppast; 11 | 12 | libclang_compilation_database get_database(const char* json) 13 | { 14 | std::ofstream file("compile_commands.json"); 15 | file << json; 16 | file.close(); 17 | 18 | return libclang_compilation_database("."); 19 | } 20 | 21 | void require_flags(const libclang_compile_config& config, const char* flags) 22 | { 23 | std::string result; 24 | auto config_flags = detail::libclang_compile_config_access::flags(config); 25 | // skip until including __cppast_version__minor__, those are the default options 26 | auto in_default = true; 27 | for (auto& config_flag : config_flags) 28 | { 29 | if (config_flag == "-D__cppast_version_minor__=" CPPAST_VERSION_MINOR) 30 | in_default = false; 31 | else if (!in_default) 32 | result += config_flag + ' '; 33 | } 34 | REQUIRE(!result.empty()); 35 | result.pop_back(); 36 | REQUIRE(result == flags); 37 | } 38 | 39 | TEST_CASE("libclang_compile_config") 40 | { 41 | // only test database parser 42 | #ifdef _WIN32 43 | auto json = R"([ 44 | { 45 | "directory": "C:/foo", 46 | "command": "/usr/bin/clang++ -Irelative -IC:/absolute -DA=FOO -DB(X)=X -c -o a.o a.cpp", 47 | "file": "a.cpp" 48 | }, 49 | { 50 | "directory": "C:/bar/", 51 | "command": "/usr/bin/clang++ -Irelative -DA=FOO -c -o b.o b.cpp", 52 | "file": "C:/b.cpp", 53 | }, 54 | { 55 | "directory": "C:/bar/", 56 | "command": "/usr/bin/clang++ -IC:/absolute -DB(X)=X -c -o b.o b.cpp", 57 | "file": "C:/b.cpp", 58 | }, 59 | { 60 | "directory": "", 61 | "command": "/usr/bin/clang++ -std=c++14 -fms-extensions -fms-compatibility -fno-strict-aliasing -c -o c.o c.cpp", 62 | "file": "C:/c.cpp", 63 | } 64 | ])"; 65 | 66 | # define CPPAST_DETAIL_DRIVE "C:" 67 | 68 | #else 69 | auto json = R"([ 70 | { 71 | "directory": "/foo", 72 | "command": "/usr/bin/clang++ -Irelative -I/absolute -DA=FOO -DB(X)=X -c -o a.o a.cpp", 73 | "file": "a.cpp" 74 | }, 75 | { 76 | "directory": "/bar/", 77 | "command": "/usr/bin/clang++ -Irelative -DA=FOO -c -o b.o b.cpp", 78 | "file": "/b.cpp", 79 | }, 80 | { 81 | "directory": "/bar/", 82 | "command": "/usr/bin/clang++ -I/absolute -DB(X)=X -c -o b.o b.cpp", 83 | "file": "/b.cpp", 84 | }, 85 | { 86 | "directory": "", 87 | "command": "/usr/bin/clang++ -std=c++14 -fms-extensions -fms-compatibility -fno-strict-aliasing -c -o c.o c.cpp", 88 | "file": "/c.cpp", 89 | } 90 | ])"; 91 | 92 | # define CPPAST_DETAIL_DRIVE 93 | 94 | #endif 95 | 96 | auto database = get_database(json); 97 | 98 | libclang_compile_config a(database, CPPAST_DETAIL_DRIVE "/foo/a.cpp"); 99 | require_flags(a, "-I" CPPAST_DETAIL_DRIVE "/foo/relative -I" CPPAST_DETAIL_DRIVE 100 | "/absolute -DA=FOO -DB(X)=X"); 101 | 102 | libclang_compile_config b(database, CPPAST_DETAIL_DRIVE "/b.cpp"); 103 | require_flags(b, "-I" CPPAST_DETAIL_DRIVE "/bar/relative -DA=FOO -I" CPPAST_DETAIL_DRIVE 104 | "/absolute -DB(X)=X"); 105 | 106 | libclang_compile_config c(database, CPPAST_DETAIL_DRIVE "/c.cpp"); 107 | require_flags(c, "-std=c++14 -fms-extensions -fms-compatibility -fno-strict-aliasing"); 108 | } 109 | -------------------------------------------------------------------------------- /test/parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace cppast; 9 | 10 | TEST_CASE("parse_files") 11 | { 12 | class null_compile_config : public compile_config 13 | { 14 | public: 15 | null_compile_config() : compile_config({}) {} 16 | 17 | private: 18 | void do_set_flags(cpp_standard, compile_flags) override {} 19 | 20 | void do_add_include_dir(std::string) override {} 21 | 22 | void do_add_macro_definition(std::string, std::string) override {} 23 | 24 | void do_remove_macro_definition(std::string) override {} 25 | 26 | const char* do_get_name() const noexcept override 27 | { 28 | return "null"; 29 | } 30 | 31 | bool do_use_c() const noexcept override 32 | { 33 | return false; 34 | } 35 | } config; 36 | 37 | class null_parser : public parser 38 | { 39 | public: 40 | using config = null_compile_config; 41 | 42 | null_parser() : parser(type_safe::ref(logger_)) {} 43 | 44 | private: 45 | std::unique_ptr do_parse(const cpp_entity_index& idx, std::string path, 46 | const compile_config&) const override 47 | { 48 | return cpp_file::builder(std::move(path)).finish(idx); 49 | } 50 | 51 | stderr_diagnostic_logger logger_; 52 | }; 53 | 54 | cpp_entity_index idx; 55 | simple_file_parser parser(type_safe::ref(idx)); 56 | 57 | auto file_names = {"a.cpp", "b.cpp", "c.cpp"}; 58 | parse_files(parser, file_names, config); 59 | 60 | auto iter = file_names.begin(); 61 | for (auto& file : parser.files()) 62 | REQUIRE(file.name() == *iter++); 63 | } 64 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | // SPDX-License-Identifier: MIT 3 | 4 | #define CATCH_CONFIG_MAIN 5 | #include 6 | -------------------------------------------------------------------------------- /test/visitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace cppast; 3 | 4 | #include "test_parser.hpp" 5 | #include 6 | 7 | TEST_CASE("visitor_filtered") 8 | { 9 | auto code = R"( 10 | namespace the_ns { 11 | class foo { 12 | enum inner_enum {}; 13 | class bar {}; 14 | }; 15 | class one {}; class two {}; class three {}; 16 | enum quaz {}; 17 | } 18 | enum outer {}; 19 | )"; 20 | 21 | cpp_entity_index idx; 22 | auto file = parse(idx, "cpp_class.cpp", code); 23 | unsigned filtered_count = 0; 24 | auto visitor_callback = [&](const cpp_entity&, cppast::visitor_info info) { 25 | if (info.event != cppast::visitor_info::container_entity_exit) 26 | ++filtered_count; 27 | return true; 28 | }; 29 | 30 | constexpr auto all_node_count = 10, enum_count = 3, class_count = 5; 31 | 32 | SECTION("all nodes are visited") 33 | { 34 | filtered_count = 0; 35 | cppast::visit(*file, [](const cpp_entity&) { return true; }, visitor_callback); 36 | REQUIRE(filtered_count == all_node_count); 37 | } 38 | 39 | SECTION("filtered callback on both enter and exit") 40 | { 41 | filtered_count = 0; 42 | cppast::visit(*file, [](const cpp_entity&) { return true; }, 43 | [&](const cpp_entity&, cppast::visitor_info info) { 44 | (void)info; 45 | filtered_count++; 46 | return true; 47 | }); 48 | REQUIRE(filtered_count == all_node_count * 2); 49 | } 50 | 51 | SECTION("whitelist") 52 | { 53 | SECTION("only one kind whitelisted") 54 | { 55 | filtered_count = 0; 56 | cppast::visit(*file, whitelist(), visitor_callback); 57 | REQUIRE(filtered_count == enum_count); 58 | } 59 | 60 | SECTION("many kinds whitelisted") 61 | { 62 | filtered_count = 0; 63 | cppast::visit(*file, whitelist(), 64 | visitor_callback); 65 | REQUIRE(filtered_count == enum_count + class_count); 66 | } 67 | } 68 | 69 | SECTION("blacklist") 70 | { 71 | SECTION("only one kind blacklisted") 72 | { 73 | filtered_count = 0; 74 | cppast::visit(*file, blacklist(), visitor_callback); 75 | REQUIRE(filtered_count == all_node_count - 1); 76 | } 77 | 78 | SECTION("many kinds blacklisted") 79 | { 80 | filtered_count = 0; 81 | cppast::visit(*file, blacklist(), 82 | visitor_callback); 83 | REQUIRE(filtered_count == all_node_count - enum_count - class_count); 84 | } 85 | } 86 | SECTION("blacklist_and_children") 87 | { 88 | SECTION("only one kind blacklisted") 89 | { 90 | filtered_count = 0; 91 | cppast::visit(*file, blacklist_and_children(), 92 | visitor_callback); 93 | REQUIRE(filtered_count == 0); 94 | } 95 | 96 | SECTION("many kinds blacklisted") 97 | { 98 | filtered_count = 0; 99 | cppast::visit(*file, 100 | blacklist_and_children(), 102 | visitor_callback); 103 | REQUIRE(filtered_count == all_node_count - enum_count - class_count); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017-2023 Jonathan Müller and cppast contributors 2 | # SPDX-License-Identifier: MIT 3 | # found in the top-level directory of this distribution. 4 | 5 | add_executable(cppast_tool main.cpp) 6 | target_link_libraries(cppast_tool PUBLIC cppast cxxopts) 7 | set_target_properties(cppast_tool PROPERTIES CXX_STANDARD 11 OUTPUT_NAME cppast) 8 | 9 | install(TARGETS cppast_tool) 10 | --------------------------------------------------------------------------------