├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── COPYRIGHT ├── LICENSE ├── README.md ├── apps ├── CMakeLists.txt ├── CallsiteLister.cc ├── FuncLister.cc ├── FuncListerAM.cc ├── FuncListerRAV.cc ├── FunctionMover.cc ├── FunctionPrinter.cc ├── GlobalDetect.cc ├── GlobalReplace.cc ├── ListCXXMemberCalls.cc ├── StructFieldUser.cc ├── TemplateType.cc ├── TemplateVarFinder.cc ├── TypedefFinder.cc ├── summarize_command_line.cc └── summarize_command_line.h ├── doc └── Doxyfile.in ├── docker ├── Dockerfile └── test_coarct.sh ├── lib ├── CMakeLists.txt ├── callsite_common.h ├── callsite_expander.h ├── callsite_lister.cc ├── callsite_lister.h ├── dump_things.cc ├── dump_things.h ├── function_common.cc ├── function_common.h ├── function_definition_lister.h ├── function_repl_gen.h ├── function_sig_matchers.h ├── function_signature_expander.h ├── global_matchers.h ├── global_variable_replacer.h ├── make_replacement.h ├── member_ref.h ├── signature_insert.cc ├── signature_insert.h ├── small_matchers.h ├── struct_field_user.h ├── template_var_matchers.h ├── types.h └── utilities.h ├── test ├── CMakeLists.txt ├── apps │ ├── foo.cc.expected │ └── foo.cc.in └── lib │ ├── callsite_expander_test.cc │ ├── callsite_lister_test.cc │ ├── clang_utilities_test.cc │ ├── function_common_test.cc │ ├── function_def_lister_test.cc │ ├── function_sig_exp_test.cc │ ├── function_sig_matchers_test.cc │ ├── global_matchers_test.cc │ ├── match_count.h │ ├── prep_code.h │ ├── small_matchers_test.cc │ ├── struct_field_users_test.cc │ ├── template_var_matchers_test.cc │ ├── test_input_fn_call.cpp │ ├── test_input_fn_sig.cpp │ ├── test_input_glob_vars.cpp │ ├── test_input_mk_ptr_ref.cpp │ ├── test_input_namespace.cpp │ ├── test_input_ns_decl.cpp │ ├── test_input_on_lhs.cpp │ ├── test_input_part_of_assignment.cpp │ ├── test_input_person.cpp │ ├── test_input_std_function.cpp │ ├── test_input_struct_field_user.cpp │ ├── test_input_struct_field_user2.cpp │ ├── test_input_template_ctor.cpp │ └── utilities_test.cc └── tools └── data-use └── score ├── .ghci ├── Setup.hs ├── score.cabal ├── src ├── Cluster.hs └── Diagonalize.hs └── tests ├── Test └── Diagonalize_Test.hs ├── TestSuite.hs └── test-main.hs /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: true 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: false 12 | AllowShortBlocksOnASingleLine: true 13 | AllowShortCaseLabelsOnASingleLine: true 14 | AllowShortFunctionsOnASingleLine: Inline 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: TopLevel 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: true 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: true 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: None 36 | BreakBeforeBraces: Custom 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: false 39 | BreakAfterJavaFieldAnnotations: false 40 | BreakStringLiterals: true 41 | ColumnLimit: 80 42 | CommentPragmas: '^ IWYU pragma:' 43 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 44 | ConstructorInitializerIndentWidth: 4 45 | ContinuationIndentWidth: 4 46 | Cpp11BracedListStyle: true 47 | DerivePointerAlignment: false 48 | DisableFormat: false 49 | ExperimentalAutoDetectBinPacking: false 50 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 51 | IncludeCategories: 52 | - Regex: '^<.*\.h>' 53 | Priority: 3 54 | - Regex: '^<.*' 55 | Priority: 2 56 | - Regex: '.*' 57 | Priority: 1 58 | IncludeIsMainRegex: '([-_](test|unittest))?$' 59 | IndentCaseLabels: true 60 | IndentWidth: 2 61 | IndentWrappedFunctionNames: false 62 | JavaScriptQuotes: Leave 63 | JavaScriptWrapImports: true 64 | KeepEmptyLinesAtTheStartOfBlocks: false 65 | MacroBlockBegin: '' 66 | MacroBlockEnd: '' 67 | MaxEmptyLinesToKeep: 1 68 | NamespaceIndentation: None 69 | ObjCBlockIndentWidth: 2 70 | ObjCSpaceAfterProperty: false 71 | ObjCSpaceBeforeProtocolList: false 72 | PenaltyBreakBeforeFirstCallParameter: 1 73 | PenaltyBreakComment: 300 74 | PenaltyBreakFirstLessLess: 120 75 | PenaltyBreakString: 1000 76 | PenaltyExcessCharacter: 1000000 77 | PenaltyReturnTypeOnItsOwnLine: 200 78 | PointerAlignment: Middle 79 | ReflowComments: true 80 | SortIncludes: true 81 | SpaceAfterCStyleCast: false 82 | SpaceBeforeAssignmentOperators: true 83 | SpaceBeforeParens: Never 84 | SpaceInEmptyParentheses: false 85 | SpacesBeforeTrailingComments: 2 86 | SpacesInAngles: false 87 | SpacesInContainerLiterals: true 88 | SpacesInCStyleCastParentheses: false 89 | SpacesInParentheses: false 90 | SpacesInSquareBrackets: false 91 | Standard: Auto 92 | TabWidth: 8 93 | UseTab: Never 94 | ... 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directories 2 | build* 3 | tools/data-use/score/dist 4 | 5 | # Files for staging 6 | docker/*tbz 7 | 8 | # Sublime project files 9 | *sublime-project 10 | *sublime-workspace 11 | 12 | # Compiled Object files 13 | *.slo 14 | *.lo 15 | *.o 16 | *.obj 17 | 18 | # Precompiled Headers 19 | *.gch 20 | *.pch 21 | 22 | # Compiled Dynamic libraries 23 | *.so 24 | *.dylib 25 | *.dll 26 | 27 | # Fortran module files 28 | *.mod 29 | *.smod 30 | 31 | # Compiled Static libraries 32 | *.lai 33 | *.la 34 | *.a 35 | *.lib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | sudo: required 4 | 5 | services: 6 | - docker 7 | 8 | compiler: 9 | - clang 10 | 11 | before_install: 12 | - docker pull tkzdockerid/corct-testenv:clang-11-0-A 13 | 14 | script: 15 | - docker run -it tkzdockerid/corct-testenv:clang-11-0-A /bin/bash test_coarct.sh $TRAVIS_BRANCH 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | cmake_minimum_required(VERSION 3.3) 3 | 4 | # Compiler-driven Refactoring with Clang Tools 5 | project(CoARCT LANGUAGES CXX) 6 | 7 | # global C++ properties 8 | 9 | # Guess cmake paths for Clang and LLVM 10 | get_filename_component(CLANG_BIN_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) 11 | set(CLANG_BASE ${CLANG_BIN_DIR}/..) 12 | message(STATUS "CLANG_BASE:" ${CLANG_BASE}) 13 | message(STATUS "CMAKE_CXX_COMPILER:" ${CMAKE_CXX_COMPILER}) 14 | if(NOT DEFINED ENV{ECLANG_CMAKE_DIR}) 15 | set(CLANG_CMAKE_DIR ${CLANG_BASE}/lib/cmake/clang) 16 | else() 17 | set(CLANG_CMAKE_DIR $ENV{ECLANG_CMAKE_DIR}) 18 | endif() 19 | if(NOT DEFINED ENV{ELLVM_CMAKE_DIR}) 20 | set(LLVM_CMAKE_DIR ${CLANG_BASE}lib/cmake/llvm) 21 | else() 22 | set(LLVM_CMAKE_DIR $ENV{ELLVM_CMAKE_DIR}) 23 | endif() 24 | include("${CLANG_CMAKE_DIR}/ClangConfig.cmake") 25 | include("${LLVM_CMAKE_DIR}/LLVMConfig.cmake") 26 | 27 | # Guess include paths for the standard C++ library. 28 | # These paths are used from CoARCT tests and applications to configure the 29 | # compilers instantiated in those programs. 30 | set(CLANG_INCLUDE_DIR1 ${CLANG_BASE}/include/c++/v1) 31 | set(CLANG_INCLUDE_DIR2 ${CLANG_BASE}/lib/clang/10.0.0/include) 32 | message(STATUS "CLANG_INCLUDE_DIR1: " ${CLANG_INCLUDE_DIR1}) 33 | add_definitions(-DCLANG_INC_DIR1="${CLANG_INCLUDE_DIR1}") 34 | add_definitions(-DCLANG_INC_DIR2="${CLANG_INCLUDE_DIR2}") 35 | 36 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") 37 | 38 | # 1. ------------ Clang/LLVM configurata ------------ 39 | set(CLANG_LIBRARIES clangTooling clangASTMatchers) 40 | 41 | # derived from looking at clang++ -v 42 | # To do: get from llvm-config 43 | set(LocalLibClang_DEFINITIONS -fPIC -fvisibility-inlines-hidden 44 | -Wall -Wno-unused-parameter -Wwrite-strings 45 | -Wcast-qual -Wmissing-field-initializers 46 | -pedantic -Wno-long-long -Wcovered-switch-default 47 | -Wnon-virtual-dtor -Wdelete-non-virtual-dtor 48 | -Werror=date-time -fno-exceptions -fno-rtti 49 | -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) 50 | add_definitions(${LocalLibClang_DEFINITIONS}) 51 | 52 | # defined in ClangConfig.cmake 53 | include_directories(${CLANG_INCLUDE_DIRS}) 54 | include_directories(${LLVM_INCLUDE_DIRS}) 55 | 56 | # terminal info 57 | message(STATUS "TINFO_LIB_DIR: " $ENV{TINFO_LIB_DIR}) 58 | find_library(TINFO_LIB tinfo PATHS $ENV{TINFO_LIB_DIR}) 59 | if(${TINFO_LIB-NOTFOUND}) 60 | message(FATAL_ERROR "Could not find tinfo library!") 61 | else() 62 | set(TINFO_LIBS ${TINFO_LIBS} ${TINFO_LIB}) 63 | endif() 64 | 65 | # 1. ----------- Boost ----------- 66 | if (NOT DEFINED BOOST_INCLUDE_DIR) 67 | if (DEFINED ENV{BOOST_DIR}) 68 | set(BOOST_INCLUDE_DIR $ENV{BOOST_DIR}) 69 | message(STATUS "BOOST_INCLUDE_DIR is ${BOOST_INCLUDE_DIR}") 70 | elseif( DEFINED ENV{BOOST_INCLUDES}) 71 | set(BOOST_INCLUDE_DIR $ENV{BOOST_INCLUDES}) 72 | message(STATUS "BOOST_INCLUDE_DIR is ${BOOST_INCLUDE_DIR}") 73 | else() 74 | message(ERROR "Error: environment variable BOOST_DIR is not defined.") 75 | return() 76 | endif() 77 | endif() 78 | include_directories(${BOOST_INCLUDE_DIR}) 79 | 80 | set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) 81 | 82 | # 2. ---------- Library ---------- 83 | add_subdirectory(lib) 84 | 85 | # 3. ---------- Unit Tests ------------ 86 | # default behaviour is to build gtests 87 | option(ENABLE_UNIT_TESTS "Enable unit tests" ON) 88 | if (DEFINED ENABLE_UNIT_TESTS ) 89 | set(CORCT_GTEST_DIR ${CMAKE_SOURCE_DIR}/test) 90 | if (IS_DIRECTORY ${CORCT_GTEST_DIR}) 91 | add_subdirectory(${CORCT_GTEST_DIR}) 92 | else() 93 | message("CORCT_GTEST_DIR:" ${CORCT_GTEST_DIR}) 94 | message("CMAKE_SOURCE_DIR:" ${CMAKE_SOURCE_DIR}) 95 | message("Warning: Test dir ${CORCT_GTEST_DIR} not found.") 96 | endif() 97 | endif() 98 | 99 | # 4. ----------- Appz ------------ 100 | 101 | add_subdirectory(apps) 102 | 103 | # 5. ----------- Doxygen ----------- 104 | 105 | if (NOT DEFINED build_api_doc) 106 | set(build_api_doc "no") 107 | endif() 108 | if (${build_api_doc} )# 109 | find_package(Doxygen) 110 | if (DOXYGEN_FOUND) 111 | message("Configuring Doxygen") 112 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) 113 | # doxygen can't make a sub-dir on the fly, so we're pre-making it here 114 | # this should correspond to the OUTPUT_DIRECTORY in the Doxyfile.in 115 | # grep OUTPUT_DIR Doxyfile | grep -v ^# | cut -d '=' -f 2 116 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxygen) 117 | add_custom_target(doc ALL 118 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 119 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 120 | COMMENT "Generating API documentation with Doxygen" VERBATIM 121 | ) 122 | endif(DOXYGEN_FOUND) 123 | endif(${build_api_doc}) 124 | 125 | # End of file 126 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Triad National Security, LLC 2 | All rights reserved. 3 | 4 | Copyright 2016. This program was produced under U.S. Government contract 89233218CNA000001 for Los Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC for the U.S. Department of Energy/National Nuclear Security Administration. The Government is granted for itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide license in this material to reproduce, prepare derivative works, distribute copies to the public, perform publicly and display publicly, and to permit others to do so. NEITHER THE GOVERNMENT NOR TRIAD NATIONAL SECURITY, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. 5 | 6 | This is open source software; you can redistribute it and/or modify it under the terms of the BSD 3-clause License. If software is modified to produce derivative works, such modified software should be clearly marked, so as not to confuse it with the version available from LANL. Full text of the BSD 3-clause License can be found in the LICENSE file in the main development branch of the repository. 7 | 8 | If software is modified to produce derivative works, such modified software should be clearly marked, so as not to confuse it with the version available from LANL. 9 | 10 | Additionally, redistribution and use in source and binary forms, with 11 | or without modification, are permitted provided that the following 12 | conditions are met: 13 | 14 | · Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 17 | · Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | · Neither the name of Los Alamos National Security, LLC, Los Alamos 22 | National Laboratory, LANL, the U.S. Government, nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY TRIAD NATIONAL SECURITY, LLC AND 27 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 28 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 29 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LOS 30 | ALAMOS NATIONAL SECURITY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY 31 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 33 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 35 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 36 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 37 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016, Los Alamos National Lab 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoARCT 2 | 3 | [![Build Status](https://travis-ci.org/lanl/CoARCT.svg?branch=clang-11.0)](https://travis-ci.org/lanl/CoARCT) 4 | 5 | Code Analysis and Refactoring with Clang Tools 6 | 7 | CoARCT (pronounced like the word "corked") is a small set of tools built on Clang's LibTooling. CoARCT demonstrates some more sustained examples of refactoring and analyzing code with AST Matchers and the clang Refactoring Tool. The goal is not to supply tools, but rather to show how one can create one's own tools. 8 | 9 | It includes library code and command line drivers that go beyond some of the (excellent! but short) tutorials that are available. The CoARCT examples are drawn from refactoring legacy codes: 10 | * Reporting which functions use which global variables; 11 | * Replacing global variables with local variables, including threading variables through a call chain; 12 | * Detecting which functions use which fields of a struct: this data can be used to analyze how to break up large structs; 13 | * Finding code associated with a classic C-style linked list; 14 | * Identifying struct fields defined with typedefs, reporting underlying types (apps/TypedefFinder.cc); 15 | * Identifying typedef; 16 | * Identify uses of a class template, such as std::vector. 17 | 18 | It also demonstrates a few useful things that were not immediately clear from the tutorials and examples I learned from, such as unit testing matchers and callbacks, and building out of the Clang/LLVM tree. 19 | 20 | Our hope is that CoARCT will help demystify the Clang AST tools to developers. If the CoARCT tools are directly useful in your work, let us know! 21 | 22 | ## Prerequisites: 23 | 1. CMake version 3+ (https://cmake.org/download/) 24 | 2. Clang and LLVM 11.0 libraries and headers (http://releases.llvm.org/download.html) 25 | 3. libtinfo 26 | 4. Boost (currently using 1.61, just needs boost/type_index in one spot) 27 | 4. Google test (currently using 1.8.0 https://github.com/google/googletest) 28 | 29 | Default branch is Clang 11.0 (older branches: 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.9, 3.8). These branches track changes in the Clang API's, so be sure to match the branch against the version of Clang you are using. 30 | 31 | ## Build 32 | 33 | 1. Make sure clang++ is in your path 34 | 1. Define these environment variables 35 | ``` 36 | CXX: Your clang++ version 11.0.x 37 | GTEST_DIR: Top level directory of google test installation 38 | BOOST_DIR: Top level of Boost (#include "boost/type_index.hpp" needs to work) 39 | TINFO_LIB_DIR: points to where libtinfo.a is installed. 40 | ``` 41 | 2. Clone the repository 42 | 3. Create a build directory 43 | 44 | ``` 45 | /home/CoARCT $ mkdir build-clang-11.0.0 46 | /home/CoARCT $ cd build-clang-11.0.0 47 | ``` 48 | 49 | 4. Run cmake, make 50 | 51 | ``` 52 | /home/CoARCT/build-clang-11.0.0 $ cmake .. 53 | /home/CoARCT/build-clang-11.0.0 $ make 54 | ``` 55 | 56 | 5. Run the unit tests 57 | 58 | ``` 59 | /home/CoARCT/build-clang-11.0.0 $ ./test/corct-unittests 60 | ... 61 | [==========] 63 tests from 16 test cases ran. (438 ms total) 62 | [ PASSED ] 63 tests. 63 | ``` 64 | 65 | ## Changes for Clang 11.0 66 | 67 | Tracking a few changes to the LLVM/Clang APIs: 68 | 69 | `NamedDecl::isHidden()` to `!NamedDecl::isUnconditionallyVisible()` 70 | 71 | Confusion with `LLVM::StringRef` vs `std::string` 72 | 73 | Needed include file for `LLVM::Module` 74 | 75 | ## Changes for Clang 10.0 76 | 77 | (Still) None! 78 | 79 | ## Changes for Clang 9.0 80 | 81 | None! (This seems too easy...) 82 | 83 | ## Changes for Clang 8.0 84 | 85 | Renamed ```getLoc(Start|End)``` to ```get(Start|End)Loc```, following Clang API change. Version bumps for Docker/Travis. 86 | 87 | ## Changes for Clang 7.0 88 | 89 | None! (Hmmm.) 90 | 91 | ## Changes for Clang 6.0 92 | 93 | Added logic to match desugared types in template variable matcher. This doesn't affect anything in Clang 5, and it keeps the Clang 6 behavior the same as before (i.e. it still "sees through" type aliases). 94 | 95 | ## Changes for Clang 5.0 96 | 97 | Minor tweaks. Hopefully CMake configuration is improved. Also added ability to configure compiler instances in unit tests; this should permit more complex test inputs. 98 | 99 | ## Known issues 100 | 101 | These issues did not arise this time with my standard build on a Mac. But I'll mention them again, in case they come up. 102 | 103 | ### futimens on OSX 104 | 105 | Building CoARCT failed on OSX with pre-built binaries from llvm.org: the function `futimens` was undefined. Workaround: build Clang and LLVM from source as described at http://clang.llvm.org/get_started.html. 106 | 107 | ### No std::is_final 108 | 109 | Building CoARCT on Linux failed with errors about `no member is_final in namespace std`. Diagnosis: That installation of Clang seems to be finding headers with an older GCC (4.8.5). Workarounds 110 | 111 | 1. set (or append) `--gcc-toolchain=/path/to/newer/gcc` to the `CXXFLAGS` environment variable when running CMake. 112 | 113 | 1. The above solution did not work on one system. In that case, overriding cxx-isystem was necessary. Pass: 114 | ``` 115 | -cxx-isystem /path/to/newer/gcc/include/c++/version -cxx-isystem /path/to/newer/gcc/include/c++//x86_64-pc-linux-gnu 116 | ``` 117 | 118 | ## Copyright 119 | 120 | Los Alamos National Security, LLC (LANS) owns the copyright to CoARCT, which it identifies internally as LA-CC-17-039. See the LICENSE file for license information. 121 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories ("${PROJECT_SOURCE_DIR}/lib") 2 | 3 | add_library(corct-support summarize_command_line.cc) 4 | 5 | set(APPS_LIBRARIES 6 | corct 7 | corct-support 8 | clangTooling 9 | ${TINFO_LIB} 10 | z 11 | c 12 | ) 13 | 14 | macro(add_coarct_exe app_name app_src) 15 | add_executable(${app_name} ${app_src} ) 16 | target_link_libraries(${app_name} ${APPS_LIBRARIES} ) 17 | endmacro() 18 | 19 | add_coarct_exe(callsite-lister CallsiteLister.cc) 20 | 21 | add_coarct_exe(function-lister FuncLister.cc) 22 | 23 | add_coarct_exe(function-mover FunctionMover.cc ) 24 | 25 | add_coarct_exe(template-vars-report TemplateVarFinder.cc ) 26 | 27 | add_coarct_exe(temp-type-report TemplateType.cc ) 28 | 29 | add_coarct_exe(function-printer FunctionPrinter.cc ) 30 | 31 | add_coarct_exe(typedef-report TypedefFinder.cc ) 32 | 33 | add_coarct_exe(global-replace GlobalReplace.cc ) 34 | 35 | add_coarct_exe(struct-field-use StructFieldUser.cc ) 36 | 37 | add_coarct_exe(func-decl-lister-rav FuncListerRAV.cc ) 38 | 39 | add_coarct_exe(func-decl-lister-am FuncListerAM.cc ) 40 | 41 | add_coarct_exe(global-detect GlobalDetect.cc ) 42 | 43 | add_coarct_exe(list-member-calls ListCXXMemberCalls.cc ) 44 | 45 | # add_coarct_exe(while-loop-detect WhileLoopFinder.cc ) 46 | 47 | # add_coarct_exe(loop-convert LoopConvert.cpp 48 | 49 | # End of file 50 | -------------------------------------------------------------------------------- /apps/CallsiteLister.cc: -------------------------------------------------------------------------------- 1 | // CallLister.cc 2 | // Feb 2, 2018 3 | 4 | /* List all the places where a target function is called, and the calling 5 | * function in a translation unit.*/ 6 | 7 | #include "callsite_lister.h" 8 | #include "clang/ASTMatchers/ASTMatchFinder.h" 9 | #include "clang/ASTMatchers/ASTMatchers.h" 10 | #include "clang/Tooling/ArgumentsAdjusters.h" 11 | #include "clang/Tooling/CommonOptionsParser.h" 12 | #include "clang/Tooling/Tooling.h" 13 | #include "llvm/Support/CommandLine.h" 14 | #include 15 | 16 | using namespace clang::tooling; 17 | using namespace llvm; 18 | using namespace clang::ast_matchers; 19 | 20 | static llvm::cl::OptionCategory csl_cat("callsite-list options"); 21 | 22 | static llvm::cl::opt verbose_compiler( 23 | "vc", 24 | llvm::cl::desc("pass -v to compiler instance (default false)"), 25 | llvm::cl::cat(csl_cat), 26 | llvm::cl::init(false)); 27 | 28 | static cl::opt target_func_string( 29 | "tf", 30 | cl::desc("target function(s), separated by commas if nec. E.g. " 31 | "-tf=\"foo,bar,baz\""), 32 | cl::value_desc("target-function-string"), 33 | cl::cat(csl_cat)); 34 | 35 | const char * addl_help = 36 | "List all calls to target functions and where they are called (excluding " 37 | "functions defined in system headers)."; 38 | 39 | void 40 | add_include_paths(ClangTool & tool); 41 | 42 | int 43 | main(int argc, const char ** argv) 44 | { 45 | CommonOptionsParser OptionsParser(argc, argv, csl_cat); 46 | ClangTool tool(OptionsParser.getCompilations(), 47 | OptionsParser.getSourcePathList()); 48 | add_include_paths(tool); 49 | // process target functions 50 | corct::vec_str targ_fns(corct::split(target_func_string, ',')); 51 | 52 | // instantiate callback and matcher 53 | corct::callsite_lister csl(targ_fns); 54 | MatchFinder finder; 55 | auto matchers = csl.matchers(); 56 | for(auto & m : matchers) { finder.addMatcher(m, &csl); } 57 | // go! 58 | int rslt = tool.run(newFrontendActionFactory(&finder).get()); 59 | std::cout << "Reported " << csl.m_num_calls << " calls\n"; 60 | return rslt; 61 | } 62 | 63 | void 64 | add_include_paths(ClangTool & tool) 65 | { 66 | // add header search paths to compiler 67 | ArgumentsAdjuster ardj1 = 68 | getInsertArgumentAdjuster(corct::clang_inc_dir1.c_str()); 69 | ArgumentsAdjuster ardj2 = 70 | getInsertArgumentAdjuster(corct::clang_inc_dir2.c_str()); 71 | tool.appendArgumentsAdjuster(ardj1); 72 | tool.appendArgumentsAdjuster(ardj2); 73 | if(verbose_compiler) { 74 | ArgumentsAdjuster ardj3 = getInsertArgumentAdjuster("-v"); 75 | tool.appendArgumentsAdjuster(ardj3); 76 | } 77 | return; 78 | } // add_include_paths 79 | 80 | // End of file 81 | -------------------------------------------------------------------------------- /apps/FuncLister.cc: -------------------------------------------------------------------------------- 1 | // FuncLister.cc 2 | // Jan 26, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* List all the functions defined in a translation unit, with other enlightening 6 | * information 7 | .*/ 8 | 9 | #include "clang/ASTMatchers/ASTMatchFinder.h" 10 | #include "clang/ASTMatchers/ASTMatchers.h" 11 | #include "clang/Tooling/ArgumentsAdjusters.h" 12 | #include "clang/Tooling/CommonOptionsParser.h" 13 | #include "clang/Tooling/Tooling.h" 14 | #include "function_definition_lister.h" 15 | #include "llvm/Support/CommandLine.h" 16 | #include 17 | 18 | using namespace clang::tooling; 19 | using namespace llvm; 20 | using namespace clang::ast_matchers; 21 | 22 | static llvm::cl::OptionCategory flt_cat("func-decl-list-am options"); 23 | 24 | static llvm::cl::opt verbose_compiler( 25 | "vc", 26 | llvm::cl::desc("pass -v to compiler instance (default false)"), 27 | llvm::cl::cat(flt_cat), 28 | llvm::cl::init(false)); 29 | 30 | const char * addl_help = 31 | "List all functions that are defined in this translation unit, excluding " 32 | "functions defined in system headers."; 33 | 34 | int 35 | main(int argc, const char ** argv) 36 | { 37 | CommonOptionsParser OptionsParser(argc, argv, flt_cat); 38 | ClangTool tool(OptionsParser.getCompilations(), 39 | OptionsParser.getSourcePathList()); 40 | // add header search paths to compiler 41 | ArgumentsAdjuster ardj1 = 42 | getInsertArgumentAdjuster(corct::clang_inc_dir1.c_str()); 43 | ArgumentsAdjuster ardj2 = 44 | getInsertArgumentAdjuster(corct::clang_inc_dir2.c_str()); 45 | tool.appendArgumentsAdjuster(ardj1); 46 | tool.appendArgumentsAdjuster(ardj2); 47 | if(verbose_compiler) { 48 | ArgumentsAdjuster ardj3 = getInsertArgumentAdjuster("-v"); 49 | tool.appendArgumentsAdjuster(ardj3); 50 | } 51 | // instantiate callback and matcher 52 | corct::FunctionDefLister fl("f_decl"); 53 | MatchFinder finder; 54 | finder.addMatcher(fl.matcher(), &fl); 55 | // go! 56 | int rslt = tool.run(newFrontendActionFactory(&finder).get()); 57 | std::cout << "Reported " << fl.m_num_funcs << " functions\n"; 58 | return rslt; 59 | } 60 | 61 | // End of file 62 | -------------------------------------------------------------------------------- /apps/FuncListerAM.cc: -------------------------------------------------------------------------------- 1 | // FuncListerAM.cc 2 | // Jan 26, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* Uses AST Matcher to list all the functions in a translation unit, 6 | * skipping the ones that are defined in headers. Compare with FuncListerRAV, 7 | * which uses RecursiveASTVisitor to do the same thing. */ 8 | 9 | #include "clang/ASTMatchers/ASTMatchFinder.h" 10 | #include "clang/ASTMatchers/ASTMatchers.h" 11 | #include "clang/Tooling/CommonOptionsParser.h" 12 | #include "clang/Tooling/Tooling.h" 13 | #include "llvm/Support/CommandLine.h" 14 | #include 15 | 16 | using namespace clang::tooling; 17 | using namespace llvm; 18 | using namespace clang::ast_matchers; 19 | 20 | uint32_t num_funcs = 0; 21 | uint32_t num_skipped_funcs = 0; 22 | 23 | void 24 | print_func(clang::FunctionDecl const * const fdecl) 25 | { 26 | std::cout << "Function '" << (fdecl->getNameAsString()) << "' defined\n"; 27 | fdecl->dump(); 28 | return; 29 | } // print_func 30 | 31 | auto 32 | mk_fn_decl_matcher() 33 | { 34 | return functionDecl(isExpansionInMainFile()).bind("fdecl"); 35 | } 36 | 37 | struct FuncPrinter : public MatchFinder::MatchCallback { 38 | void run(MatchFinder::MatchResult const & result) override 39 | { 40 | using namespace clang; 41 | FunctionDecl const * fdecl = result.Nodes.getNodeAs("fdecl"); 42 | if(fdecl) { 43 | num_funcs++; 44 | print_func(fdecl); 45 | } 46 | else { 47 | std::cerr << "Invalid fdecl\n"; 48 | } 49 | return; 50 | } // run 51 | 52 | }; // FuncPrinter 53 | 54 | /* The RAV approach also makes a note when the analysis skips a function 55 | * (because it's not part of the main file). Here is an AST Matcher way of 56 | * accomplishing the same thing. */ 57 | auto 58 | mk_fn_skipper_matcher() 59 | { 60 | return functionDecl(unless(isExpansionInMainFile())).bind("fdecl"); 61 | } 62 | 63 | struct FuncSkipper : public MatchFinder::MatchCallback { 64 | void run(MatchFinder::MatchResult const & result) override 65 | { 66 | using namespace clang; 67 | FunctionDecl const * fdecl = result.Nodes.getNodeAs("fdecl"); 68 | if(fdecl) { 69 | std::cout << "Skipping " << fdecl->getNameAsString() 70 | << " not from target file\n"; 71 | num_skipped_funcs++; 72 | } 73 | else { 74 | std::cerr << "Invalid fdecl\n"; 75 | } 76 | return; 77 | } // run 78 | }; // FuncSkipper 79 | 80 | static llvm::cl::OptionCategory flt_cat("func-decl-list-am options"); 81 | 82 | int 83 | main(int argc, const char ** argv) 84 | { 85 | CommonOptionsParser OptionsParser(argc, argv, flt_cat); 86 | ClangTool Tool(OptionsParser.getCompilations(), 87 | OptionsParser.getSourcePathList()); 88 | FuncPrinter fp; 89 | FuncSkipper fs; 90 | MatchFinder finder; 91 | finder.addMatcher(mk_fn_decl_matcher(), &fp); 92 | finder.addMatcher(mk_fn_skipper_matcher(), &fs); 93 | int rslt = Tool.run(newFrontendActionFactory(&finder).get()); 94 | std::cout << "Reported " << num_funcs << " functions\n"; 95 | std::cout << "Skipped " << num_skipped_funcs << " functions\n"; 96 | return rslt; 97 | } 98 | 99 | // End of file 100 | -------------------------------------------------------------------------------- /apps/FuncListerRAV.cc: -------------------------------------------------------------------------------- 1 | // FuncListerRAV.cc 2 | // Jan 25, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* Uses RecrusiveASTVisitor to list all the functions in a translation unit, 6 | * skipping the ones that are defined in headers. Compare with FuncListerAM, 7 | * which uses AST Matchers to do the same thing. 8 | */ 9 | 10 | #include "clang/AST/ASTConsumer.h" 11 | #include "clang/AST/RecursiveASTVisitor.h" 12 | #include "clang/Frontend/CompilerInstance.h" 13 | #include "clang/Frontend/FrontendAction.h" 14 | #include "clang/Tooling/CommonOptionsParser.h" 15 | #include "clang/Tooling/Tooling.h" 16 | 17 | #include 18 | 19 | uint32_t num_funcs = 0; 20 | uint32_t num_skipped_funcs = 0; 21 | 22 | void 23 | print_func(clang::FunctionDecl * fdecl) 24 | { 25 | std::cout << "Function '" << (fdecl->getNameAsString()) << "' defined\n"; 26 | fdecl->dump(); 27 | return; 28 | } // print_func 29 | 30 | class FunctionLister : public clang::RecursiveASTVisitor { 31 | public: 32 | clang::ASTContext * ast_ctx_; 33 | 34 | explicit FunctionLister(clang::CompilerInstance * ci) 35 | : ast_ctx_(&(ci->getASTContext())) 36 | { 37 | } 38 | 39 | bool VisitFunctionDecl(clang::FunctionDecl * fdecl) 40 | { 41 | clang::SourceManager & sm(ast_ctx_->getSourceManager()); 42 | // cf cfe-3.9.0.src/include/clang/ASTMatchers/ASTMatcher.h:209-214 43 | bool const inMainFile( 44 | sm.isInMainFile(sm.getExpansionLoc(fdecl->getBeginLoc()))); 45 | if(inMainFile) { 46 | num_funcs++; 47 | print_func(fdecl); 48 | } 49 | else { 50 | std::cout << "Skipping " << fdecl->getNameAsString() 51 | << " not from target file\n"; 52 | num_skipped_funcs++; 53 | } 54 | return true; 55 | } // VisitFunctionDecl 56 | }; // FunctionLister 57 | 58 | class FunctionListerConsumer : public clang::ASTConsumer { 59 | public: 60 | virtual void HandleTranslationUnit(clang::ASTContext & ctx) 61 | { 62 | lister_.TraverseDecl(ctx.getTranslationUnitDecl()); 63 | } 64 | 65 | explicit FunctionListerConsumer(clang::CompilerInstance * ci) : lister_(ci) {} 66 | 67 | private: 68 | FunctionLister lister_; 69 | }; // FunctionListerConsumer 70 | 71 | class FuncListerAction : public clang::ASTFrontendAction { 72 | public: 73 | virtual std::unique_ptr CreateASTConsumer( 74 | clang::CompilerInstance & ci, 75 | llvm::StringRef file) 76 | { 77 | return std::unique_ptr(new FunctionListerConsumer(&ci)); 78 | } 79 | }; // FuncListerAction 80 | 81 | static llvm::cl::OptionCategory flt_cat("func-decl-list options"); 82 | 83 | int 84 | main(int argc, const char ** argv) 85 | { 86 | using namespace clang::tooling; 87 | CommonOptionsParser op(argc, argv, flt_cat); 88 | ClangTool tool(op.getCompilations(), op.getSourcePathList()); 89 | int result = tool.run(newFrontendActionFactory().get()); 90 | std::cout << "Reported " << num_funcs << " functions\n"; 91 | std::cout << "Skipped " << num_skipped_funcs << " functions\n"; 92 | return result; 93 | } 94 | // End of file 95 | -------------------------------------------------------------------------------- /apps/FunctionMover.cc: -------------------------------------------------------------------------------- 1 | // FunctionMover.cc 2 | // Mar 19, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* Motivation: move a function definition from one file to another. 6 | * This application demonstrates matching the function, recovering the source, 7 | * and cutting the source from the original file. */ 8 | 9 | #include "dump_things.h" 10 | #include "make_replacement.h" 11 | #include "types.h" 12 | #include "utilities.h" 13 | 14 | #include "clang/Frontend/FrontendActions.h" 15 | #include "clang/Lex/Lexer.h" 16 | #include "clang/Tooling/CommonOptionsParser.h" 17 | #include "clang/Tooling/Refactoring.h" 18 | #include "llvm/Support/CommandLine.h" 19 | #include 20 | #include 21 | 22 | using namespace clang::tooling; 23 | using namespace llvm; 24 | using clang::SourceLocation; 25 | using clang::SourceManager; 26 | 27 | void 28 | check_invalid(bool & invalid, const char * filename, int line); 29 | 30 | SourceLocation 31 | end_of_the_end(SourceLocation const & start_of_end, SourceManager & sm) 32 | { 33 | using namespace clang; 34 | LangOptions lopt; 35 | return Lexer::getLocForEndOfToken(start_of_end, 0, sm, lopt); 36 | } 37 | 38 | struct Function_Mover : public clang::ast_matchers::MatchFinder::MatchCallback { 39 | using repl_map_t = std::map; 40 | // using repl_map_t = std::map; 41 | 42 | std::string const fd_bd_name_ = "f_decl"; 43 | 44 | auto matcher(std::string const & fname) 45 | { 46 | using namespace clang::ast_matchers; 47 | // clang-format off 48 | return 49 | functionDecl( 50 | hasName(fname) 51 | ).bind(fd_bd_name_); 52 | // clang-format on 53 | } // matcher 54 | 55 | virtual void run(corct::result_t const & result) override 56 | { 57 | using namespace clang; 58 | FunctionDecl * f_decl = const_cast( 59 | result.Nodes.getNodeAs(fd_bd_name_)); 60 | if(f_decl) { 61 | SourceManager & sm(result.Context->getSourceManager()); 62 | SourceRange decl_range(f_decl->getSourceRange()); 63 | SourceLocation decl_begin(decl_range.getBegin()); 64 | SourceLocation decl_start_end(decl_range.getEnd()); 65 | SourceLocation decl_end_end(end_of_the_end(decl_start_end, sm)); 66 | const char * buff_begin(sm.getCharacterData(decl_begin)); 67 | const char * buff_end(sm.getCharacterData(decl_end_end)); 68 | std::string const func_string(buff_begin, buff_end); 69 | // now you have original source of declaration, output to new file etc. 70 | std::cout << "Captured function " << f_decl->getNameAsString() 71 | << " declaration:\n'''\n" 72 | << func_string << "\n'''\n"; 73 | // Generate a replacement to eliminate the function declaration in 74 | // the original source 75 | uint32_t const decl_length = 76 | sm.getFileOffset(decl_end_end) - sm.getFileOffset(decl_begin); 77 | Replacement repl(sm, decl_begin, decl_length, ""); 78 | // now add to the replacements for the source file in which this 79 | // declaration was found 80 | auto ref_filename = sm.getFilename(decl_begin); 81 | std::string filename{ref_filename.str()}; 82 | if(repls_[filename].add(repl)) { 83 | std::cerr << "Failed to enter replacement to map for file " << filename 84 | << "\n"; 85 | } 86 | } 87 | else { 88 | corct::check_ptr(f_decl, "f_decl"); 89 | } 90 | return; 91 | } // run 92 | 93 | explicit Function_Mover(repl_map_t & repls) : repls_(repls) {} 94 | 95 | repl_map_t & repls_; 96 | }; // struct Function_Mover 97 | 98 | static llvm::cl::OptionCategory FMOpts("Common options for function-mover"); 99 | 100 | const char * addl_help = 101 | "(Incomplete) Demo of moving function from one file to another"; 102 | 103 | int 104 | main(int argc, const char ** argv) 105 | { 106 | using namespace corct; 107 | CommonOptionsParser opt_prs(argc, argv, FMOpts, addl_help); 108 | RefactoringTool tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 109 | Function_Mover fm(tool.getReplacements()); 110 | finder_t finder; 111 | std::string const function_name("foo"); // could get from CL options 112 | finder.addMatcher(fm.matcher(function_name), &fm); 113 | // runs, reports, does not overwrite: 114 | // tool.run(newFrontendActionFactory(&finder).get()); 115 | // invoke instead to overwrite original source: 116 | tool.runAndSave(newFrontendActionFactory(&finder).get()); 117 | 118 | for(auto & p : tool.getReplacements()) { 119 | auto & fname = p.first; 120 | auto & repls = p.second; 121 | std::cout << "Replacements collected for file \"" << fname 122 | << "\" (not applied):\n"; 123 | for(auto & r : repls) { std::cout << "\t" << r.toString() << "\n"; } 124 | } 125 | return 0; 126 | } // main 127 | 128 | void 129 | check_invalid(bool & invalid, const char * filename, int line) 130 | { 131 | if(invalid) { 132 | printf("%s:%i getCharacterData returned invalid\n", filename, line); 133 | } 134 | invalid = false; 135 | } 136 | 137 | // End of file 138 | -------------------------------------------------------------------------------- /apps/FunctionPrinter.cc: -------------------------------------------------------------------------------- 1 | // FunctionPrinter.cc 2 | // Mar 17, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* Report function declarations with a given name. */ 6 | 7 | #include "dump_things.h" 8 | #include "make_replacement.h" 9 | #include "types.h" 10 | #include "utilities.h" 11 | 12 | #include "clang/Frontend/FrontendActions.h" 13 | #include "clang/Lex/Lexer.h" 14 | #include "clang/Tooling/CommonOptionsParser.h" 15 | #include "clang/Tooling/Refactoring.h" 16 | #include "llvm/Support/CommandLine.h" 17 | #include 18 | #include 19 | 20 | using namespace clang::tooling; 21 | using namespace llvm; 22 | using clang::SourceLocation; 23 | using clang::SourceManager; 24 | 25 | void 26 | check_invalid(bool & invalid, const char * filename, int line); 27 | 28 | SourceLocation 29 | end_of_the_end(SourceLocation const & start_of_end, SourceManager & sm) 30 | { 31 | using namespace clang; 32 | LangOptions lopt; 33 | return Lexer::getLocForEndOfToken(start_of_end, 0, sm, lopt); 34 | } 35 | 36 | struct Function_Printer 37 | : public clang::ast_matchers::MatchFinder::MatchCallback { 38 | std::string const fd_bd_name_ = "f_decl"; 39 | 40 | auto matcher(std::string const & fname) 41 | { 42 | using namespace clang::ast_matchers; 43 | // clang-format off 44 | return 45 | functionDecl( 46 | hasName(fname) 47 | ).bind(fd_bd_name_); 48 | // clang-format on 49 | } // matcher 50 | 51 | virtual void run(corct::result_t const & result) override 52 | { 53 | using namespace clang; 54 | FunctionDecl * f_decl = const_cast( 55 | result.Nodes.getNodeAs(fd_bd_name_)); 56 | if(f_decl) { 57 | SourceManager & sm(result.Context->getSourceManager()); 58 | SourceRange decl_range(f_decl->getSourceRange()); 59 | SourceLocation decl_begin(decl_range.getBegin()); 60 | SourceLocation decl_end_end(end_of_the_end(decl_range.getEnd(), sm)); 61 | const char * buff_begin(sm.getCharacterData(decl_begin)); 62 | const char * buff_end(sm.getCharacterData(decl_end_end)); 63 | std::string const func_string(buff_begin, buff_end); 64 | std::cout << "Captured function " << f_decl->getNameAsString() 65 | << " declaration:\n'''\n" 66 | << func_string << "\n'''\n"; 67 | } 68 | else { 69 | corct::check_ptr(f_decl, "f_decl"); 70 | } 71 | return; 72 | } // run 73 | }; // struct Function_Printer 74 | 75 | static llvm::cl::OptionCategory FPOpts("Common options for function-printer"); 76 | 77 | const char * addl_help = "Print function definitions with given name"; 78 | 79 | static llvm::cl::opt function_name( 80 | "f", 81 | cl::desc("Function name to search for"), 82 | cl::value_desc("function-name"), 83 | cl::cat(FPOpts), 84 | cl::init("foo")); 85 | 86 | int 87 | main(int argc, const char ** argv) 88 | { 89 | using namespace corct; 90 | CommonOptionsParser opt_prs(argc, argv, FPOpts, addl_help); 91 | RefactoringTool Tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 92 | Function_Printer fp; 93 | finder_t finder; 94 | finder.addMatcher(fp.matcher(function_name), &fp); 95 | Tool.run(newFrontendActionFactory(&finder).get()); 96 | return 0; 97 | } // main 98 | 99 | void 100 | check_invalid(bool & invalid, const char * filename, int line) 101 | { 102 | if(invalid) { 103 | printf("%s:%i getCharacterData returned invalid\n", filename, line); 104 | } 105 | invalid = false; 106 | } 107 | 108 | // End of file 109 | -------------------------------------------------------------------------------- /apps/GlobalDetect.cc: -------------------------------------------------------------------------------- 1 | // GlobalDetect.cc 2 | // Oct. 6, 2016 3 | // (c) Copyright 2016-7 LANSLLC, all rights reserved 4 | 5 | #include "clang/Tooling/CommonOptionsParser.h" 6 | #include "clang/Tooling/Tooling.h" 7 | #include "global_matchers.h" 8 | #include "llvm/Support/CommandLine.h" 9 | #include "summarize_command_line.h" 10 | #include 11 | 12 | using namespace clang::tooling; 13 | using namespace llvm; 14 | using namespace clang::ast_matchers; 15 | 16 | const char * addl_help = 17 | "Report all functions that use global variable, or all sites at which " 18 | "global variables are used"; 19 | 20 | // command line options: 21 | static llvm::cl::OptionCategory GDOpts("global-detect options"); 22 | 23 | static cl::opt old_var_string( 24 | "old", 25 | cl::desc("global variable to seek (default: detect all globals)"), 26 | cl::value_desc("old-var-string"), 27 | cl::cat(GDOpts), 28 | cl::init("")); 29 | 30 | static cl::opt report_functions( 31 | "f", 32 | cl::desc("just report functions that use the target global(s)"), 33 | cl::cat(GDOpts), 34 | cl::init(false)); 35 | 36 | static cl::opt export_opts("xp", 37 | cl::desc("export command line options"), 38 | cl::value_desc("bool"), 39 | cl::cat(GDOpts), 40 | cl::init(false)); 41 | 42 | int 43 | main(int argc, const char ** argv) 44 | { 45 | using namespace corct; 46 | CommonOptionsParser OptionsParser(argc, argv, GDOpts, addl_help); 47 | ClangTool Tool(OptionsParser.getCompilations(), 48 | OptionsParser.getSourcePathList()); 49 | 50 | if(export_opts) { 51 | summarize_command_line("global-detect", addl_help); 52 | return 0; 53 | } 54 | 55 | Global_Printer printer(std::cout); 56 | StatementMatcher global_var_matcher = 57 | (old_var_string == "") ? all_global_var_matcher() 58 | : mk_global_var_matcher(old_var_string); 59 | DeclarationMatcher global_func_matcher = 60 | (old_var_string == "") ? all_global_fn_matcher() 61 | : mk_global_fn_matcher(old_var_string); 62 | 63 | clang::ast_matchers::MatchFinder finder; 64 | if(report_functions) { finder.addMatcher(global_func_matcher, &printer); } 65 | else { 66 | finder.addMatcher(global_var_matcher, &printer); 67 | } 68 | return Tool.run(newFrontendActionFactory(&finder).get()); 69 | } // main 70 | 71 | // End of file 72 | -------------------------------------------------------------------------------- /apps/GlobalReplace.cc: -------------------------------------------------------------------------------- 1 | // LoopConvert.cc 2 | // Aug 17, 2016 3 | // (c) Copyright 2016 LANSLLC, all rights reserved 4 | 5 | /* Like GlobalDetect, only now we're trying to replace some stuff. */ 6 | 7 | #include "callsite_expander.h" 8 | #include "dump_things.h" 9 | #include "function_signature_expander.h" 10 | #include "global_variable_replacer.h" 11 | #include "make_replacement.h" 12 | #include "utilities.h" 13 | 14 | #include "clang/AST/ASTContext.h" 15 | #include "clang/AST/Type.h" 16 | #include "clang/ASTMatchers/ASTMatchFinder.h" 17 | #include "clang/ASTMatchers/ASTMatchers.h" 18 | #include "clang/Basic/LangOptions.h" 19 | #include "clang/Frontend/FrontendActions.h" 20 | #include "clang/Tooling/CommonOptionsParser.h" 21 | #include "clang/Tooling/Core/Replacement.h" 22 | #include "clang/Tooling/Refactoring.h" 23 | #include "clang/Tooling/Tooling.h" 24 | #include "llvm/Support/CommandLine.h" 25 | #include "summarize_command_line.h" 26 | #include 27 | #include 28 | 29 | using namespace clang::tooling; 30 | using namespace llvm; 31 | 32 | using corct::vec_str; 33 | 34 | const char * addl_help = 35 | "Replace global variable references with locals, or thread new local " 36 | "variables through call chains"; 37 | 38 | // static llvm::cl::OptionCategory XpndOpts("Expanding function signatures"); 39 | 40 | static llvm::cl::OptionCategory CompilationOpts("Global Replace options:"); 41 | 42 | static llvm::cl::opt expand_func( 43 | "Xpnd", 44 | llvm::cl::desc("insert new parameter NP to target function tf, new arg " 45 | "(NA) to calls to tf"), 46 | llvm::cl::cat(CompilationOpts), 47 | llvm::cl::init(false)); 48 | 49 | static cl::opt new_func_param_string( 50 | "np", 51 | cl::desc("param to add to the global-using functions' signature (with " 52 | "-xpnd), e.g. -np=\"SimConfig const & sim_config\""), 53 | cl::value_desc("new-param-string"), 54 | cl::cat(CompilationOpts)); 55 | 56 | static cl::opt new_func_arg_string( 57 | "na", 58 | cl::desc("argument to add to the global-using functions' call sites (with " 59 | "-xpnd), e.g. -na=\"sim_config\""), 60 | cl::value_desc("new-arg-string"), 61 | cl::cat(CompilationOpts)); 62 | 63 | // static llvm::cl::OptionCategory RrOpts( 64 | // "Fixing/replacing references to globals"); 65 | 66 | static cl::opt rep_refs( 67 | "R", 68 | cl::desc( 69 | "replace references to global vars (leave function signatures alone)"), 70 | cl::cat(CompilationOpts), 71 | cl::init(false)); 72 | 73 | static cl::opt old_var_string( 74 | "gvar", 75 | cl::desc("global variable(s) to replace, comma separated (with -R), e.g. " 76 | "-old=\"NR,NB\""), 77 | cl::value_desc("old-var-string"), 78 | cl::cat(CompilationOpts)); 79 | 80 | static cl::opt new_var_string( 81 | "lvar", 82 | cl::desc("each global variable's replacement, comma separated, resp. to " 83 | "old-var-string; e.g. -new=\"sim_cgf.NR,sim_cfg.NB\""), 84 | cl::value_desc("new-var-string"), 85 | cl::cat(CompilationOpts)); 86 | 87 | // CommonOptionsParser declares HelpMessage with a description of the common 88 | // command-line options related to the compilation database and input files. 89 | // It's nice to have this help message in all tools. 90 | static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); 91 | 92 | // A help message for this specific tool can be added afterwards. 93 | static cl::extrahelp MoreHelp( 94 | "Replace global variables by inserting local variables\n" 95 | "into call chains. Both expands function signatures in declarations\n" 96 | "and epxands callsites. References to global variable names are\n" 97 | "replaced with references to the local variable names."); 98 | 99 | // some command line options: 100 | // static llvm::cl::OptionCategory GROpts("Common options for global-replace"); 101 | 102 | static cl::opt target_func_string( 103 | "tf", 104 | cl::desc("target function(s) to modify, separated by commas if nec. E.g. " 105 | "-tf=\"foo,bar,baz\""), 106 | cl::value_desc("target-function-string"), 107 | cl::cat(CompilationOpts)); 108 | 109 | static cl::opt dry_run("d", 110 | cl::desc("dry run"), 111 | cl::cat(CompilationOpts), 112 | cl::init(false)); 113 | 114 | static cl::opt export_opts("xp", 115 | cl::desc("export command line options"), 116 | cl::value_desc("bool"), 117 | cl::cat(CompilationOpts), 118 | cl::init(false)); 119 | 120 | void 121 | announce_dry(bool const dry_run_) 122 | { 123 | if(dry_run_) { std::cout << "This is a dry run\n"; } 124 | else { 125 | std::cout << "This is not a dry run\n"; 126 | } 127 | return; 128 | } // announce_dry 129 | 130 | void 131 | list_compilations(CommonOptionsParser & opt_prs) 132 | { 133 | auto & comps(opt_prs.getCompilations()); 134 | std::cout << "# of compile commands: " << comps.getAllCompileCommands().size() 135 | << "\n"; 136 | std::cout << "Sources from compilation:\n"; 137 | for(auto & source : opt_prs.getSourcePathList()) { 138 | std::cout << source << "\n"; 139 | } 140 | return; 141 | } 142 | 143 | int 144 | main(int argc, const char ** argv) 145 | { 146 | using corct::replacements_map_t; 147 | using corct::split; 148 | CommonOptionsParser opt_prs(argc, argv, CompilationOpts, addl_help); 149 | if(export_opts) { 150 | corct::summarize_command_line("global-replace", addl_help); 151 | return 0; 152 | } 153 | RefactoringTool tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 154 | 155 | announce_dry(dry_run); 156 | list_compilations(opt_prs); 157 | 158 | vec_str old_var_strings(split(old_var_string, ',')); 159 | vec_str new_var_strings(split(new_var_string, ',')); 160 | if(old_var_strings.size() != new_var_strings.size()) { 161 | std::cerr << "Must have one replacement for each global variable!\n"; 162 | return -1; 163 | } 164 | 165 | replacements_map_t & rep_map = tool.getReplacements(); 166 | 167 | corct::global_variable_replacer v_replacer(rep_map, old_var_strings, 168 | new_var_strings, dry_run); 169 | 170 | // sort out target functions 171 | vec_str targ_fns(split(target_func_string, ',')); 172 | 173 | corct::function_signature_expander f_expander(rep_map, targ_fns, 174 | new_func_param_string, dry_run); 175 | 176 | corct::expand_callsite s_expander(rep_map, targ_fns, new_func_arg_string, 177 | dry_run); 178 | 179 | clang::ast_matchers::MatchFinder finder; 180 | 181 | corct::global_variable_replacer::matchers_t global_ref_matchers = 182 | v_replacer.matchers(); 183 | corct::function_signature_expander::matchers_t exp_matchers = 184 | f_expander.fn_matchers(); 185 | corct::expand_callsite::matchers_t site_matchers = s_expander.fn_matchers(); 186 | 187 | std::cout << targ_fns.size() << " targets, along with " << exp_matchers.size() 188 | << " matchers\n"; 189 | 190 | if(rep_refs) { 191 | for(auto & m : global_ref_matchers) { finder.addMatcher(m, &v_replacer); } 192 | } 193 | else if(expand_func) { 194 | std::cout << "Expanding functions\n"; 195 | for(uint32_t i = 0; i < site_matchers.size(); ++i) { 196 | finder.addMatcher(site_matchers[i], &s_expander); 197 | finder.addMatcher(exp_matchers[i], &f_expander); 198 | } 199 | } 200 | 201 | tool.runAndSave(newFrontendActionFactory(&finder).get()); 202 | 203 | llvm::outs() << "Replacements collected: \n"; 204 | for(auto & p : tool.getReplacements()) { 205 | llvm::outs() << "file: " << p.first << ":\n"; 206 | for(auto & r : p.second) { llvm::outs() << r.toString() << "\n"; } 207 | } 208 | return 0; 209 | } // main 210 | 211 | // End of file 212 | -------------------------------------------------------------------------------- /apps/ListCXXMemberCalls.cc: -------------------------------------------------------------------------------- 1 | // ListCXXMemberCalls.cc 2 | // Oct 26, 2018 3 | // (c) Copyright 2018 LANSLLC, all rights reserved 4 | 5 | /* Demonstrate AST Matcher to list all cxx member calls in a namespace. 6 | * This was inspired by Stack Overflow #52993315 */ 7 | 8 | #include "clang/ASTMatchers/ASTMatchFinder.h" 9 | #include "clang/ASTMatchers/ASTMatchers.h" 10 | #include "clang/Tooling/CommonOptionsParser.h" 11 | #include "clang/Tooling/Tooling.h" 12 | #include "dump_things.h" 13 | #include "llvm/Support/CommandLine.h" 14 | #include "utilities.h" 15 | #include 16 | 17 | using namespace clang::tooling; 18 | using namespace llvm; 19 | using namespace clang::ast_matchers; 20 | 21 | /* Make a matcher for call expressions in namespace ns_name */ 22 | auto 23 | mk_call_expr_matcher(std::string const & ns_name) 24 | { 25 | /* There is more than one way to write an AST matcher. Here are three looks 26 | * at accomplishing (or trying to accomplish) the same goal. */ 27 | 28 | /* First: the easy way of writing this matcher. It might be inefficient in a 29 | * large project, if it matched many call expressions, only to reject 30 | * them because the enclosing namespace was wrong. But it is correct. */ 31 | // return cxxMemberCallExpr(hasAncestor(namespaceDecl(hasName(ns_name)))) 32 | // .bind("call"); 33 | 34 | /* Second: try to match first on namespace, then on call expr. But i't 35 | * work as wanted--it will stop after the first match! */ 36 | // return namespaceDecl(hasName(ns_name), 37 | // hasDescendant(cxxMemberCallExpr().bind("call"))); 38 | 39 | /* Third: match first on namespace, then use forEachDescendant to match all 40 | * the callexpr's. */ 41 | return namespaceDecl(hasName(ns_name), 42 | forEachDescendant(cxxMemberCallExpr().bind("call"))); 43 | } 44 | 45 | /* CallPrinter::run() will be called when a match is found */ 46 | struct CallPrinter : public MatchFinder::MatchCallback { 47 | void run(MatchFinder::MatchResult const & result) override 48 | { 49 | using namespace clang; 50 | SourceManager & sm(result.Context->getSourceManager()); 51 | CXXMemberCallExpr const * call = 52 | result.Nodes.getNodeAs("call"); 53 | if(call) { 54 | num_calls++; 55 | auto const method_name(call->getMethodDecl()->getNameAsString()); 56 | auto const callee_name(call->getRecordDecl()->getNameAsString()); 57 | std::cout << "Method '" << method_name << "' invoked by object of type '" 58 | << callee_name << "' at " 59 | << corct::locationAsString(call->getBeginLoc(), &sm) << "\n"; 60 | } 61 | else { 62 | corct::check_ptr(call, "call"); 63 | } 64 | return; 65 | } // run 66 | 67 | uint32_t num_calls = 0; 68 | }; // CallPrinter 69 | 70 | static llvm::cl::OptionCategory mem_cat("list-member-call options"); 71 | 72 | static cl::opt ns_name_string("ns", 73 | cl::desc("namespace"), 74 | cl::value_desc("ns"), 75 | cl::cat(mem_cat), 76 | cl::init("")); 77 | 78 | int 79 | main(int argc, const char ** argv) 80 | { 81 | CommonOptionsParser OptionsParser(argc, argv, mem_cat); 82 | ClangTool Tool(OptionsParser.getCompilations(), 83 | OptionsParser.getSourcePathList()); 84 | CallPrinter cp; 85 | MatchFinder finder; 86 | 87 | finder.addMatcher(mk_call_expr_matcher(ns_name_string), &cp); 88 | int rslt = Tool.run(newFrontendActionFactory(&finder).get()); 89 | std::cout << "Reported " << cp.num_calls << " member calls\n"; 90 | return rslt; 91 | } 92 | 93 | // End of file 94 | -------------------------------------------------------------------------------- /apps/StructFieldUser.cc: -------------------------------------------------------------------------------- 1 | // StructFieldUser.cc 2 | // Oct. 25, 2016 3 | // (c) Copyright 2016 LANSLLC, all rights reserved 4 | 5 | /* Find which functions use which fields. */ 6 | 7 | #include "dump_things.h" 8 | #include "make_replacement.h" 9 | #include "struct_field_user.h" 10 | #include "summarize_command_line.h" 11 | #include "utilities.h" 12 | 13 | #include "clang/Frontend/FrontendActions.h" 14 | #include "clang/Tooling/CommonOptionsParser.h" 15 | #include "clang/Tooling/Refactoring.h" 16 | #include "llvm/Support/CommandLine.h" 17 | #include 18 | 19 | using namespace clang::tooling; 20 | using namespace llvm; 21 | 22 | const char * addl_help = 23 | "For specified structs, find which functions read/write which fields"; 24 | 25 | static llvm::cl::OptionCategory SFUOpts("Common options for struct-field-use"); 26 | 27 | static cl::opt target_struct_string( 28 | "ts", 29 | cl::desc("target struct(s), separated by commas if nec. E.g. " 30 | "-ts=\"cell_t,bas_t,region_t\""), 31 | cl::value_desc("target-struct-string"), 32 | cl::cat(SFUOpts)); 33 | 34 | static cl::opt export_opts("xp", 35 | cl::desc("export command line options"), 36 | cl::value_desc("bool"), 37 | cl::cat(SFUOpts), 38 | cl::init(false)); 39 | 40 | /** Print out in various possibly useful ways. */ 41 | template 42 | void 43 | print_fields(MapOMapOSet const & m); 44 | 45 | int 46 | main(int argc, const char ** argv) 47 | { 48 | using namespace corct; 49 | CommonOptionsParser opt_prs(argc, argv, SFUOpts, addl_help); 50 | if(export_opts) { 51 | summarize_command_line("struct-field-use", addl_help); 52 | return 0; 53 | } 54 | RefactoringTool Tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 55 | vec_str targ_fns(split(target_struct_string, ',')); 56 | struct_field_user s_finder(targ_fns); 57 | struct_field_user::matchers_t field_matchers = s_finder.matchers(); 58 | finder_t finder; 59 | for(auto m : field_matchers) { finder.addMatcher(m, &s_finder); } 60 | Tool.run(newFrontendActionFactory(&finder).get()); 61 | std::cout << "Fields written:\n"; 62 | print_fields(s_finder.lhs_uses_); 63 | std::cout << "Fields accessed, but not written:\n"; 64 | print_fields(s_finder.non_lhs_uses_); 65 | return 0; 66 | } // main 67 | 68 | template 69 | void 70 | print_fields(MapOMapOSet const & m) 71 | { 72 | using corct::string_t; 73 | corct::string_t tabs(""); 74 | for(auto map_it : m) { 75 | string_t const s_name = (map_it.first); 76 | for(auto mm_it : (map_it.second)) { 77 | string_t const f_name = mm_it.first; 78 | // tabs = corct::add_tab(tabs); 79 | for(auto membr : mm_it.second) { 80 | std::cout << tabs << f_name << " " << s_name << " " << membr << "\n"; 81 | } 82 | // tabs = corct::remove_tab(tabs); 83 | } 84 | } 85 | return; 86 | } // print_fields 87 | 88 | // End of file 89 | -------------------------------------------------------------------------------- /apps/TemplateType.cc: -------------------------------------------------------------------------------- 1 | // TemplateType.cc 2 | // June 7, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* For variables that are constructor expressions, and with type that is 6 | * a class template specialization, list its template arguments. */ 7 | 8 | #include "dump_things.h" 9 | #include "make_replacement.h" 10 | #include "types.h" 11 | #include "utilities.h" 12 | 13 | #include "clang/Frontend/FrontendActions.h" 14 | #include "clang/Tooling/CommonOptionsParser.h" 15 | #include "clang/Tooling/Refactoring.h" 16 | #include "llvm/Support/CommandLine.h" 17 | #include 18 | 19 | using namespace clang::tooling; 20 | using namespace llvm; 21 | 22 | struct TemplateType_Reporter 23 | : public clang::ast_matchers::MatchFinder::MatchCallback { 24 | std::string const ctor_bd_name_ = "ctor_expr"; 25 | std::string const var_bd_name_ = "var_decl"; 26 | std::string const sp_dcl_bd_name_ = "spec_decl"; 27 | 28 | auto matcher() 29 | { 30 | using namespace clang::ast_matchers; 31 | // clang-format off 32 | return 33 | varDecl( 34 | has( 35 | cxxConstructExpr().bind(ctor_bd_name_) 36 | ) 37 | ,hasType( 38 | classTemplateSpecializationDecl().bind(sp_dcl_bd_name_) 39 | ) 40 | ).bind(var_bd_name_); 41 | // clang-format on 42 | } // matcher 43 | 44 | virtual void run(corct::result_t const & result) override 45 | { 46 | using namespace clang; 47 | using corct::check_ptr; 48 | using CTSD = ClassTemplateSpecializationDecl; 49 | SourceManager & sm(result.Context->getSourceManager()); 50 | CTSD * spec_decl = 51 | const_cast(result.Nodes.getNodeAs(sp_dcl_bd_name_)); 52 | VarDecl * var_decl = 53 | const_cast(result.Nodes.getNodeAs(var_bd_name_)); 54 | if(spec_decl && var_decl) { 55 | // get the template arguments 56 | TemplateArgumentList const & tal(spec_decl->getTemplateArgs()); 57 | for(unsigned i = 0; i < tal.size(); ++i) { 58 | TemplateArgument const & ta(tal[i]); 59 | // If this arg is a type arg, get its name 60 | TemplateArgument::ArgKind k(ta.getKind()); 61 | std::string argName = ""; 62 | if(k == TemplateArgument::ArgKind::Type) { 63 | QualType t = ta.getAsType(); 64 | argName = t.getAsString(); 65 | } 66 | // Could do similar for integral args, etc... 67 | std::cout << "For variable declared at " 68 | << corct::sourceRangeAsString(var_decl->getSourceRange(), &sm) 69 | << ":" << spec_decl->getNameAsString() << ": template arg " 70 | << (i + 1) << ": " << argName << std::endl; 71 | } 72 | } 73 | else { 74 | check_ptr(spec_decl, "spec_decl"); 75 | check_ptr(var_decl, "var_decl"); 76 | } 77 | return; 78 | } // run 79 | }; // struct Typedef_Reporter 80 | 81 | static llvm::cl::OptionCategory TROpts("Common options for temp-type-report"); 82 | 83 | const char * addl_help = 84 | "Report on variables that are template specializations"; 85 | 86 | int 87 | main(int argc, const char ** argv) 88 | { 89 | using namespace corct; 90 | CommonOptionsParser opt_prs(argc, argv, TROpts, addl_help); 91 | RefactoringTool Tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 92 | TemplateType_Reporter tr; 93 | finder_t finder; 94 | finder.addMatcher(tr.matcher(), &tr); 95 | Tool.run(newFrontendActionFactory(&finder).get()); 96 | return 0; 97 | } // main 98 | 99 | // End of file 100 | -------------------------------------------------------------------------------- /apps/TemplateVarFinder.cc: -------------------------------------------------------------------------------- 1 | // TemplateVarFinder.cc 2 | // Nov 15, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* Find variables of a given template type, record the template type args for 6 | * that variable, and then process that data. Current processing generates 7 | * a tuple of the set of all types used in the template. 8 | * 9 | * For example, suppose you look for all variables of type std::vector, and the 10 | * program creates std::vector, std::vector and 11 | * std::vector: this produces tuple (order not 12 | * guaranteed). */ 13 | #include "template_var_matchers.h" 14 | #include "types.h" 15 | #include "utilities.h" 16 | 17 | #include "clang/Frontend/FrontendActions.h" 18 | #include "clang/Tooling/ArgumentsAdjusters.h" 19 | #include "clang/Tooling/CommonOptionsParser.h" 20 | #include "clang/Tooling/Refactoring.h" 21 | #include "llvm/Support/CommandLine.h" 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace llvm; 27 | 28 | // Command line support 29 | static llvm::cl::OptionCategory TVFOpts( 30 | "Common options for template-var-report"); 31 | 32 | const char * addl_help = 33 | "Gather up all the types with which a template is instantiated; print" 34 | " a tuple of the set of those types."; 35 | 36 | static cl::opt template_name( 37 | "tn", 38 | cl::desc("Pattern of template to match, e.g.\"vector\""), 39 | cl::value_desc("template-name-pattern"), 40 | cl::cat(TVFOpts)); 41 | 42 | static cl::opt namespace_name( 43 | "nn", 44 | cl::desc("Optional namespace to limit search e.g.\"std\" to search for " 45 | "\"std::vector\""), 46 | cl::value_desc("namespace-name"), 47 | cl::cat(TVFOpts), 48 | cl::init("")); 49 | 50 | using type_set_t = std::set; 51 | using map_args_t = corct::template_var_reporter::map_args_t; 52 | using vec_strs_t = corct::template_var_reporter::vec_strs_t; 53 | 54 | // Functions that process the results 55 | /**\brief distill the results into a set*/ 56 | type_set_t 57 | collate_types(map_args_t const & args); 58 | 59 | /** \brief Remove 'class ', 'struct ', '__1::', and ' ' */ 60 | void 61 | fix_class(corct::string_t & s); 62 | 63 | /**\brief Remove substring from s. */ 64 | void 65 | seek_and_remove(corct::string_t & s, corct::string_t const & substr); 66 | 67 | /**\brief process the set of types into result, in this case a tuple written 68 | * to a stringstream. */ 69 | void 70 | process_type_set(type_set_t const & ts, std::ostream & s); 71 | 72 | int 73 | main(int argc, const char ** argv) 74 | { 75 | using namespace corct; 76 | using namespace clang::tooling; 77 | using tvr_t = template_var_reporter; 78 | CommonOptionsParser opt_prs(argc, argv, TVFOpts, addl_help); 79 | RefactoringTool tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 80 | // Alert the compiler instance to std lib header locations 81 | ArgumentsAdjuster ardj1 = getInsertArgumentAdjuster(clang_inc_dir1.c_str()); 82 | ArgumentsAdjuster ardj2 = getInsertArgumentAdjuster(clang_inc_dir2.c_str()); 83 | tool.appendArgumentsAdjuster(ardj1); 84 | tool.appendArgumentsAdjuster(ardj2); 85 | // examine command line arguments 86 | if(template_name.empty()) { 87 | printf("%s:%i Must specify a template to search for!\n", __FUNCTION__, 88 | __LINE__); 89 | return -1; 90 | } 91 | // Configure the callback object, matchers, finder 92 | tvr_t tr(template_name); 93 | if(!namespace_name.empty()) { tr.namespace_name_ = namespace_name; } 94 | finder_t finder; 95 | tvr_t::matchers_t ms(tr.matchers()); 96 | for(auto & m : ms) { finder.addMatcher(m, &tr); } 97 | // run the tool 98 | tool.run(newFrontendActionFactory(&finder).get()); 99 | // process the results 100 | type_set_t t(collate_types(tr.args_)); 101 | std::stringstream s; 102 | process_type_set(t, s); 103 | std::cout << s.str(); 104 | return 0; 105 | } // main 106 | 107 | type_set_t 108 | collate_types(map_args_t const & args) 109 | { 110 | std::set type_set; 111 | for(auto p : args) { 112 | vec_strs_t const & type_args(p.second); 113 | for(auto & t : type_args) { type_set.insert(t); } 114 | } 115 | return type_set; 116 | } // collate_types 117 | 118 | void 119 | fix_class(corct::string_t & s) 120 | { 121 | corct::string_t struct_str("struct "); 122 | corct::string_t class_str("class "); 123 | corct::string_t ns_str("__1::"); 124 | seek_and_remove(s, struct_str); 125 | seek_and_remove(s, class_str); 126 | seek_and_remove(s, ns_str); 127 | seek_and_remove(s, " "); 128 | return; 129 | } // fix_class 130 | 131 | void 132 | seek_and_remove(corct::string_t & s, corct::string_t const & substr) 133 | { 134 | size_t n = s.find(substr); 135 | if(n != std::string::npos) { 136 | s.replace(n, substr.size(), ""); 137 | return fix_class(s); 138 | } 139 | return; 140 | } 141 | 142 | void 143 | process_type_set(type_set_t const & ts, std::ostream & s) 144 | { 145 | s << "using types = std::tuple<\n"; 146 | size_t n_ts(ts.size()); 147 | size_t i(0); 148 | for(auto & t1 : ts) { 149 | std::string t(t1); 150 | fix_class(t); 151 | s << "\t" << t; 152 | if(i++ < (n_ts - 1)) { s << ",\n"; } 153 | } 154 | s << ">;\n"; 155 | return; 156 | } // process_type_set 157 | 158 | // End of file 159 | -------------------------------------------------------------------------------- /apps/TypedefFinder.cc: -------------------------------------------------------------------------------- 1 | // TypedefFinder.cc 2 | // Feb 14, 2017 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | /* Find all C struct fields declared with a typedef; report the typedef and 6 | * underlying (desugared) type. Ignores fields declared as builtin types. */ 7 | 8 | #include "dump_things.h" 9 | #include "make_replacement.h" 10 | #include "types.h" 11 | #include "utilities.h" 12 | 13 | #include "clang/Frontend/FrontendActions.h" 14 | #include "clang/Tooling/CommonOptionsParser.h" 15 | #include "clang/Tooling/Refactoring.h" 16 | #include "llvm/Support/CommandLine.h" 17 | #include 18 | 19 | using namespace clang::tooling; 20 | using namespace llvm; 21 | 22 | struct Typedef_Reporter 23 | : public clang::ast_matchers::MatchFinder::MatchCallback { 24 | std::string const ty_bd_name_ = "type_decl"; 25 | std::string const fd_bd_name_ = "fld_decl"; 26 | 27 | auto matcher() 28 | { 29 | using namespace clang::ast_matchers; 30 | // clang-format off 31 | return 32 | fieldDecl( 33 | hasType( 34 | typedefType().bind(ty_bd_name_) 35 | )//hasType 36 | ).bind(fd_bd_name_); 37 | // clang-format on 38 | } // matcher 39 | 40 | virtual void run(corct::result_t const & result) override 41 | { 42 | using namespace clang; 43 | FieldDecl * f_decl = 44 | const_cast(result.Nodes.getNodeAs(fd_bd_name_)); 45 | TypedefType * tt = const_cast( 46 | result.Nodes.getNodeAs(ty_bd_name_)); 47 | if(f_decl && tt) { 48 | // QualType qt = tt->desugar(); // good to see 49 | QualType ut = tt->getDecl()->getUnderlyingType(); 50 | TypedefNameDecl * tnd = tt->getDecl(); 51 | std::string const struct_name = f_decl->getParent()->getNameAsString(); 52 | std::string const fld_name = f_decl->getNameAsString(); 53 | // std::string const ty_name = qt.getAsString(); 54 | std::string ut_name = ut.getAsString(); 55 | std::string tnd_name = tnd->getNameAsString(); 56 | std::cout << "Struct '" << struct_name << "' declares field '" << fld_name 57 | << " with typedef name = '" << tnd_name << "'" 58 | << ", underlying type = '" << ut_name << "'" << std::endl; 59 | } 60 | else { 61 | corct::check_ptr(f_decl, "f_decl"); 62 | corct::check_ptr(tt, "tt"); 63 | } 64 | return; 65 | } // run 66 | }; // struct Typedef_Reporter 67 | 68 | static llvm::cl::OptionCategory TROpts("Common options for typedef-report"); 69 | 70 | const char * addl_help = "Find structs with fields declared via typedef"; 71 | 72 | int 73 | main(int argc, const char ** argv) 74 | { 75 | using namespace corct; 76 | CommonOptionsParser opt_prs(argc, argv, TROpts, addl_help); 77 | RefactoringTool Tool(opt_prs.getCompilations(), opt_prs.getSourcePathList()); 78 | Typedef_Reporter tr; 79 | finder_t finder; 80 | finder.addMatcher(tr.matcher(), &tr); 81 | Tool.run(newFrontendActionFactory(&finder).get()); 82 | return 0; 83 | } // main 84 | 85 | // End of file 86 | -------------------------------------------------------------------------------- /apps/summarize_command_line.cc: -------------------------------------------------------------------------------- 1 | // summarize_command_line.cc 2 | // T. M. Kelley 3 | // (c) Copyright 2017 LANSLLC, all rights reserved 4 | 5 | #include "summarize_command_line.h" 6 | #include "llvm/Support/CommandLine.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace corct { 13 | void 14 | print_header(std::ostream & o, corct::str_t_cr ex_name, corct::str_t_cr ovvw) 15 | { 16 | o << "{\"executable\" : \"" << ex_name << "\"," 17 | << "\n\"overview\": \"" << ovvw << "\"," 18 | << "\n\"options\": [\n"; 19 | return; 20 | } 21 | 22 | void 23 | print_footer(std::ostream & o) 24 | { 25 | o << "]\n" 26 | << "}"; 27 | return; 28 | } 29 | 30 | template 31 | bool 32 | in_set(set & s, typename set::value_type & val) 33 | { 34 | return s.end() != s.find(val); 35 | } 36 | 37 | corct::string_t 38 | escape(corct::str_t_cr in_s) 39 | { 40 | corct::string_t s; 41 | std::set e_chars = {'\"'}; 42 | for(char c : in_s) { 43 | if(in_set(e_chars, c)) { s += "\\"; } 44 | s += c; 45 | } 46 | return s; 47 | } 48 | 49 | std::map builtin_opts = {{"extra-arg", ""}, 50 | {"extra-arg-before", ""}, 51 | {"p", ""}}; 52 | 53 | bool 54 | is_builtin(string_t const & key) 55 | { 56 | return builtin_opts.end() != builtin_opts.find(key); 57 | } // is_builtin 58 | 59 | /* TODO: we don't have a good way to access the description for LLVM 60 | * "builtin" options. For right now, this is just broken. */ 61 | void 62 | print_option(std::ostream & s, llvm::cl::Option & o) 63 | { 64 | // std::cout << "\n\nOption info: "; 65 | // o.printOptionInfo(30); 66 | // std::cout << "\nOption Value: "; 67 | // o.printOptionValue(o.getOptionWidth(),false); 68 | // std::cout << "\n---------------------------------\n"; 69 | string_t key(o.ArgStr.str()); 70 | s << " {\"option\" : {\n" 71 | << " \"name\" : \"" << key << "\",\n"; 72 | if(!o.ValueStr.str().empty()) { 73 | s << " \"value\" : \"" << o.ValueStr.str() << "\",\n"; 74 | } 75 | else if(is_builtin(key)) { 76 | s << " \"value\" : \"" << builtin_opts[key] << "\",\n"; 77 | } 78 | else { 79 | s << " \"value\" : \"NONENADAZILCH\",\n"; 80 | } 81 | s << " \"desc\" : \"" << escape(o.HelpStr.str()) << "\"}}"; 82 | } 83 | 84 | void 85 | summarize_command_line(corct::str_t_cr command_name, corct::str_t_cr ovvw) 86 | { 87 | using namespace llvm::cl; 88 | using namespace corct; 89 | /* This list is arbitrary--it's a guess at things that won't interest most 90 | end users. The exception is 'help'; that conflicts with 'help' in 91 | Python's argparser. Sigh. */ 92 | set_str excluded_opts = {"opt-bisect-limit", 93 | "help", 94 | "help-hidden", 95 | "xp", 96 | "view-background", 97 | "pass-remarks-analysis", 98 | "pass-remarks-missed", 99 | "stats", 100 | "as-secure-log-file-name", 101 | "rng-seed", 102 | "pass-remarks", 103 | "asm-macro-max-nesting-depth", 104 | "stats-json", 105 | "track-memory", 106 | "static-func-full-module-prefix", 107 | "info-output-file"}; 108 | std::stringstream fname; 109 | fname << command_name << ".json"; 110 | std::ofstream s(fname.str()); 111 | if(!s) { 112 | std::cerr << "Cannot open output file '" << fname.str() << "'\n"; 113 | return; 114 | } 115 | std::cout << "Generating command line summary in '" << fname.str() << "'\n"; 116 | print_header(s, command_name, ovvw); 117 | bool after_the_first(false); 118 | llvm::StringMap