pax_global_header00006660000000000000000000000064140216275050014514gustar00rootroot0000000000000052 comment=3f80c31d4c6456eb0e2f615238a925ec8a81e052 cvise-2.3.0/000077500000000000000000000000001402162750500126275ustar00rootroot00000000000000cvise-2.3.0/.gitattributes000066400000000000000000000000531402162750500155200ustar00rootroot00000000000000* text=auto CMakeLists.txt export-subst cvise-2.3.0/.github/000077500000000000000000000000001402162750500141675ustar00rootroot00000000000000cvise-2.3.0/.github/workflows/000077500000000000000000000000001402162750500162245ustar00rootroot00000000000000cvise-2.3.0/.github/workflows/build.yml000066400000000000000000000034221402162750500200470ustar00rootroot00000000000000name: Build on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build_and_test: runs-on: ubuntu-latest strategy: matrix: llvm: [9, 10, 11] build-type: [DEBUG] docker: [opensuse/tumbleweed] include: - llvm: 11 build-type: ASAN docker: opensuse/tumbleweed - llvm: 11 build-type: UBSAN docker: opensuse/tumbleweed - llvm: 11 build-type: COVERAGE docker: opensuse/tumbleweed - llvm: 9 build-type: DEBUG docker: opensuse/leap fail-fast: false container: ${{ matrix.docker }} steps: - run: zypper -n install binutils clang${{ matrix.llvm }}-devel cmake flex gcc-c++ llvm${{ matrix.llvm }}-devel python3-Pebble python3-pytest unifdef python3-psutil curl git python3-pytest-flake8 python3-flake8 python3-flake8-builtins python3-flake8-bugbear python3-flake8-import-order python3-flake8-quotes - run: zypper -n install python3-pip python3-flake8-comprehensions python3 sqlite-devel if: matrix.docker == 'opensuse/tumbleweed' - run: pip install codecov pytest-cov if: matrix.docker == 'opensuse/tumbleweed' - uses: actions/checkout@v2 - run: nproc - name: build run: | mkdir objdir cd objdir cmake .. -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} make -j`nproc` VERBOSE=1 - name: test run: | cd objdir pytest if: matrix.build-type != 'COVERAGE' - name: test with coverage run: | cd objdir pytest --cov=./ codecov if: matrix.build-type == 'COVERAGE' cvise-2.3.0/.gitignore000066400000000000000000000016551402162750500146260ustar00rootroot00000000000000# Files made by compilation. .deps/ .libs/ *.a *.la *.lo *.o *.obj cvise-*.tar.gz # Files made by Eclipse CDT. .autotools .cproject .project # CMake generated files CMakeCache.txt CMakeFiles cmake_install.cmake install_manifest.txt *.vcxproj *.vcxproj.filters *.sln ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## User-specific files *.suo *.user *.userosscache *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ x86/ objdir/ # Visual Studio 2015 cache/options directory .vs/ # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Python cache files __pycache__ *.pyc .pytest_cache # pyenv files .python-version cvise-2.3.0/AUTHORS000066400000000000000000000005361402162750500137030ustar00rootroot00000000000000-*- mode: Text -*- C-Reduce was written by Yang Chen, Eric Eide, and John Regehr at the University of Utah. Yang Chen Eric Eide John Regehr C-Vise was written by Moritz Pflanzer and Martin Liška Moritz Pflanzer Martin Liška cvise-2.3.0/CMakeLists.txt000066400000000000000000000154531402162750500153770ustar00rootroot00000000000000## -*- mode: CMake -*- ## ## Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah ## All rights reserved. ## ## This file is distributed under the University of Illinois Open Source ## License. See the file COPYING for details. ############################################################################### cmake_minimum_required(VERSION 2.8.12) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") include(CheckIncludeFile) include(CheckCXXCompilerFlag) include(GetGitRevisionDescription) project(cvise) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) message(FATAL_ERROR "CMAKE_SOURCE_DIR should be different from PROJECT_BINARY_DIR") endif() ############################################################################### # Locate LLVM and check its version. Do this here because we need the LLVM # package definitions in the "CMakeLists.txt" files for multiple subdirs. # find_package(LLVM REQUIRED CONFIG NO_CMAKE_BUILDS_PATH) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in ${LLVM_DIR}") if (${LLVM_PACKAGE_VERSION} VERSION_LESS "9.0") message(FATAL_ERROR "C-Vise requires LLVM 9.0 or later") endif() # # Do this here, too, just to keep it with the LLVM check above. # find_package(Clang REQUIRED CONFIG NO_CMAKE_BUILDS_PATH) message(STATUS "Using ClangConfig.cmake in ${Clang_DIR}") # Locate Python and check its version. # find_package(PythonInterp 3.6 REQUIRED) # Locate pytest execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pytest --version OUTPUT_VARIABLE PYTEST_output ERROR_VARIABLE PYTEST_error RESULT_VARIABLE PYTEST_result) if(NOT ${PYTEST_result} EQUAL 0) message(WARNING "Pytest package not available: ${PYTEST_error}") endif() # Locate Pebble execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pebble" OUTPUT_VARIABLE PEBBLE_output ERROR_VARIABLE PEBBLE_error RESULT_VARIABLE PEBBLE_result) if(NOT ${PEBBLE_result} EQUAL 0) message(WARNING "Pebble package not available: ${PEBBLE_error}") endif() # Locate psutil execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import psutil" OUTPUT_VARIABLE PSUTIL_output ERROR_VARIABLE PSUTIL_error RESULT_VARIABLE PSUTIL_result) if(NOT ${PSUTIL_result} EQUAL 0) message(WARNING "psutil package not available: ${PSUTIL_error}") endif() # Locate flex. Do this here because we need the package definitions in the # "CMakeLists.txt" files for multiple subdirs. # find_package(FLEX REQUIRED) find_program(UNIFDEF unifdef) if(NOT UNIFDEF) message(WARNING "unifdef not available") endif() ############################################################################### # Determine the short git hash for the source tree. # ## METHOD 1: The source tree is the result of `git archive'. # `git archive' inserts the abbreviated hash of the archive's commit into this # file. (See the `.gitattributes' file.) # set(GIT_HASH "3f80c31") if(GIT_HASH MATCHES "^\\$") ## METHOD 2: The source tree is a git repository. get_git_head_revision(GIT_REFSPEC GIT_HASH) if(NOT GIT_HASH STREQUAL "GITDIR-NOTFOUND") # Trim to the short hash. string(SUBSTRING "${GIT_HASH}" 0 7 GIT_HASH) else() ## METHOD 3: Give up. set(GIT_HASH "unknown") endif() endif() ############################################################################### # Generate the "config.h" file. # set(ENABLE_TRANS_ASSERT ON CACHE BOOL "Use assert() in clang_delta transformations.") check_include_file("dlfcn.h" HAVE_DLFCN_H) check_include_file("inttypes.h" HAVE_INTTYPES_H) check_include_file("memory.h" HAVE_MEMORY_H) check_include_file("stdint.h" HAVE_STDINT_H) check_include_file("stdlib.h" HAVE_STDLIB_H) check_include_file("strings.h" HAVE_STRINGS_H) check_include_file("string.h" HAVE_STRING_H) check_include_file("sys/stat.h" HAVE_SYS_STAT_H) check_include_file("sys/types.h" HAVE_SYS_TYPES_H) check_include_file("unistd.h" HAVE_UNISTD_H) set(cvise_PACKAGE "cvise") set(cvise_PACKAGE_BUGREPORT "https://github.com/marxin/cvise/issues") set(cvise_PACKAGE_NAME "cvise") set(cvise_PACKAGE_STRING "cvise 2.3.0") set(cvise_PACKAGE_TARNAME "cvise") set(cvise_PACKAGE_URL "https://github.com/marxin/cvise/") set(cvise_PACKAGE_VERSION "2.3.0") set(cvise_VERSION "2.3.0") set(cvise_LLVM_VERSION "${LLVM_PACKAGE_VERSION}") configure_file("cmake_config.h.in" "${PROJECT_BINARY_DIR}/config.h") add_definitions("-DHAVE_CONFIG_H") ############################################################################### # Use option `-fvisibility-inlines-hidden` if the C++ compiler supports it. # See LLVM file `share/llvm/cmake/HandleLLVMOptions.cmake`. # check_cxx_compiler_flag( "-fvisibility-inlines-hidden" SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG ) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # XXX figure out how to get "-std=c++14 -fno-rtti" from LLVM. That's how we # get those options in the Automake path... set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fno-rtti -fno-strict-aliasing -Wall -Wextra -Wno-unused-parameter") if(SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden") endif() set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror") endif() ############################################################################### # Enable tests enable_testing() add_test(NAME all COMMAND ${PYTHON_EXECUTABLE} -m pytest) ############################################################################### # Needs to be sourced after we have a compiler tested include(GNUInstallDirs) add_subdirectory(clang_delta) add_subdirectory(clex) add_subdirectory(cvise) add_subdirectory(delta) # Copy top-level cvise script configure_file( "${PROJECT_SOURCE_DIR}/cvise.py" "${PROJECT_BINARY_DIR}/cvise.py" @ONLY ) configure_file( "${PROJECT_SOURCE_DIR}/cvise-delta.py" "${PROJECT_BINARY_DIR}/cvise-delta.py" @ONLY ) configure_file( "${PROJECT_SOURCE_DIR}/tests/test_cvise.py" "${PROJECT_BINARY_DIR}/tests/test_cvise.py" COPYONLY ) configure_file( "${PROJECT_SOURCE_DIR}/tests/sources/blocksort-part.c" "${PROJECT_BINARY_DIR}/tests/sources/blocksort-part.c" COPYONLY ) configure_file( "${PROJECT_SOURCE_DIR}/setup.cfg" "${PROJECT_BINARY_DIR}/setup.cfg" COPYONLY ) install(PROGRAMS "${PROJECT_BINARY_DIR}/cvise.py" DESTINATION "${CMAKE_INSTALL_BINDIR}" RENAME "cvise" ) install(PROGRAMS "${PROJECT_BINARY_DIR}/cvise-delta.py" DESTINATION "${CMAKE_INSTALL_BINDIR}" RENAME "cvise-delta" ) ############################################################################### ## End of file. cvise-2.3.0/COPYING000066400000000000000000000034441402162750500136670ustar00rootroot00000000000000-*- mode: Text -*- C-Vise is Copyright (c) 2020 Martin Liška and Moritz Pflanzer. Based on C-Reduce with Copyright (c) 2011-2020 The University of Utah. C-Vise is distributed under the following license, which is often called the "University of Illinois Open Source License." // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal with the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimers in the // documentation and/or other materials provided with the distribution. // // * Neither the names of the University of Utah nor the names of its // contributors may be used to endorse or promote products derived from // this Software without specific prior written permission. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // WITH THE SOFTWARE. cvise-2.3.0/CREDUCE_MERGE000066400000000000000000000001121402162750500145350ustar00rootroot00000000000000Last cherry-picked git revision: c32c5c327758a047ae10e55a2465ba54293dfff9 cvise-2.3.0/INSTALL.md000066400000000000000000000061011402162750500142550ustar00rootroot00000000000000# Installing C-Vise ## Using a Package Manager Before compiling C-Vise yourself, you might want to see if your OS comes with a pre-compiled package for C-Vise. ### openSUSE Tumbleweed ```shell zypper in cvise ``` ### Gentoo Linux ```shell emerge cvise ``` ### Fedora ```shell yum install cvise ``` ### Debian bullseye ```shell apt install cvise ``` ### Using Docker (or Podman) ```shell $ podman run -it opensuse/tumbleweed bash 714d543633e1 $ zypper -n install cvise 714d543633e1 $ cvise --version cvise 1.2.0 ``` ## From Source ### Prereqs C-Vise is written in Python 3, C++, and C. To compile and run C-Vise, you will need a development environment that supports these languages. C-Vise's build system requires CMake. Beyond the basic compile/build tools, C-Vise depends on a set of third-party software packages, including LLVM. On Ubuntu or Mint, the prerequisites other than LLVM can be installed like this: ``` sudo apt-get install \ flex build-essential unifdef ``` On FreeBSD 12.1, the prerequisites can be installed like this: ``` sudo pkg install \ llvm90 flex ``` Otherwise, install these packages either manually or using the package manager: * [Flex](http://flex.sourceforge.net/) * [LLVM/Clang 9.0.0 or later](http://llvm.org/releases/download.html) (No need to compile it: the appropriate "pre-built binaries" package is all you need. For example, the openSUSE Tumbleweed provides them by `llvm10-devel` and `clang10-devel` packages. * [Python 3.6+](https://www.python.org/downloads/) * [Pebble](https://pypi.org/project/Pebble/) * [psutil](https://pypi.org/project/psutil/) * [CMake](https://cmake.org/) * [unifdef](http://dotat.at/prog/unifdef/) Optional packages: * [pytest](https://docs.pytest.org/en/latest/) ## Building and installing C-Vise You can configure, build, and install C-Vise with the CMake. From either the source directory or a build directory: ``` cmake [source-dir] [options] make make install ``` If LLVM/Clang is not in your search path, you can tell CMake where to find LLVM/Clang: ``` # Use the LLVM/Clang tree rooted at /opt/llvm cmake [source-dir] -DCMAKE_PREFIX_PATH=/opt/llvm ``` Alternatively, if you choose to build LLVM and Clang yourself, you can set the `LLVM_DIR` and/or `Clang_DIR` variables to paths where CMake can find the `LLVMConfig.cmake` and/or `ClangConfig.cmake` files. The value of `LLVM_DIR` is usually `./lib/cmake/llvm`, relative to your LLVM build or install directory. Similarly, the value of `Clang_DIR` is usually `./lib/cmake/clang`, relative to your Clang build or install directory. For example: ``` # Use separate LLVM and Clang build trees, /work/my-{llvm,clang} cmake [source-dir] -DLLVM_DIR=/work/my-llvm/lib/cmake/llvm \ -DClang_DIR=/work/my-clang/lib/cmake/clang ``` You do *not* need to set `Clang_DIR` if you build Clang within your LLVM tree. Also, note that you must actually *build* LLVM and Clang before building C-Vise. Note that assertions are enabled by default. To disable assertions: ``` cmake ... -DENABLE_TRANS_ASSERT=OFF ``` ## Testing You can test the project with: ``` make test ``` cvise-2.3.0/README.md000066400000000000000000000104701402162750500141100ustar00rootroot00000000000000# C-Vise [![OBS master](https://build.opensuse.org/assets/favicon-ac48595b97f38c2425d7ea77739a63d771fcda9f73cc8c474b66461c0836fc2a.ico)](https://build.opensuse.org/package/show/home:marxin:cvise-github/cvise) ![GitHub Actions](https://github.com/marxin/cvise/workflows/Build/badge.svg) [![Total alerts](https://img.shields.io/lgtm/alerts/g/marxin/cvise.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/marxin/cvise/alerts/) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/marxin/cvise.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/marxin/cvise/context:python) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/marxin/cvise.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/marxin/cvise/context:cpp) [![codecov](https://codecov.io/gh/marxin/cvise/branch/master/graph/badge.svg)](https://codecov.io/gh/marxin/cvise) ## About C-Vise is a super-parallel Python port of the [C-Reduce](https://github.com/csmith-project/creduce/). The port is fully compatible to the C-Reduce and uses the same efficient LLVM-based C/C++ reduction tool named `clang_delta`. C-Vise is a tool that takes a large C, C++ or OpenCL program that has a property of interest (such as triggering a compiler bug) and automatically produces a much smaller C/C++ or OpenCL program that has the same property. It is intended for use by people who discover and report bugs in compilers and other tools that process C/C++ or OpenCL code. The project also contains a simple wrapper `cvise-delta` which simulates the same behavior as original [delta](http://delta.tigris.org/) tool (but in super-parallel way). *NOTE:* C-Vise happens to do a pretty good job reducing the size of programs in languages other than C/C++, such as JavaScript and Rust. If you need to reduce programs in some other language, please give it a try. ## Speed Comparison I made a comparison for couple of GCC bug reports on my AMD Ryzen 7 2700X Eight-Core Processor machine with the following results: | Test-case | Size | C-Vise Reduction | C-Reduce Reduction | Speed Up | | --- | --- | --- | --- | --- | | [PR92516](http://gcc.gnu.org/PR92516) | 6.5 MB | 35m | 77m | 220% | | [PR94523](http://gcc.gnu.org/PR94523) | 2.1 MB | 15m | 33m | 220% | | [PR94632](http://gcc.gnu.org/PR94632) | 3.3 MB | 20m | 28m | 40% | | [PR94937](http://gcc.gnu.org/PR94937) | 8.5 MB | 242m | 303m | 125% | ## Installation See [INSTALL.md](INSTALL.md). ## Usage example The C-Vise can be used for a reduction of a compiler crash. In this case, let's consider an existing [PR94534](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94534): Original test-case (`pr94534.C` file): ```c++ template class Demo { struct { Demo* p; } payload{this}; friend decltype(payload); }; int main() { Demo d; } ``` The program crashes in GCC, but is accepted with Clang: ```console $ g++ pr94534.C -c pr94534.C: In instantiation of ‘class Demo’: pr94534.C:13:13: required from here pr94534.C:7:5: internal compiler error: Segmentation fault 7 | } payload{this}; | ^~~~~~~ 0x10a1d8f crash_signal /home/marxin/Programming/gcc/gcc/toplev.c:328 0x7ffff78fef1f ??? /usr/src/debug/glibc-2.31-4.1.x86_64/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0 0xae31a8 instantiate_class_template_1 /home/marxin/Programming/gcc/gcc/cp/pt.c:11973 ... $ clang++ pr94534.C -c ``` So let's build a reduction script so that it will grep for `instantiate_class_template_1` on the standard error output and that it compiles with Clang: `reduce-ice.sh`: ```shell #!/bin/sh g++ pr94534.C -c 2>&1 | grep 'instantiate_class_template_1' && clang++ -c pr94534.C ``` The reduction can be then run with: ```console $ cvise ./reduce-ice.sh pr94534.C INFO ===< 30356 >=== INFO running 16 interestingness tests in parallel INFO INITIAL PASSES INFO ===< IncludesPass >=== ... template class a { int b; friend decltype(b); }; void c() { a d; } ``` ## Notes 1. C-Vise creates temporary directories in `$TMPDIR` and so usage of a `tmpfs` directory is recommended. 1. Each invocation of the interestingness test is performed in a fresh temporary directory containing a copy of the file that is being reduced. If your interestingness test requires access to other files, you should either copy them into the current working directory or else refer to them using an absolute path. cvise-2.3.0/TODO000066400000000000000000000062261402162750500133250ustar00rootroot00000000000000-*- mode: Text -*- -------------------------------------------------------------------- C-Vise pre-release list: - make sure copyright years are up to date - test on Windows, Linux, OS X -------------------------------------------------------------------- C-Vise TODO list: turn if (foo) goto bar; baz; bar: into if (!foo) baz it would be nice to have a way to glue multiple C/C++ files into a single compilation unit, as an alternative to multi-file reduction - CIL can do this but it's pretty invasive make llvm-svn-compatible build against a specific LLVM version the CI is the problem here could solve it like we do in Souper with a pre-built LLVM tarball add modes for Rust and Javascript add optional pass timeout? more shortcut keys? constant folding partial #define processing remove zero-length files at the end of reduction? in localize_headers, correctly deal with the case where the original C/C++ file is in the current dir maybe implement passes to: ensure that identifiers first appear in sorted order identifiers are dense reduce the non-header-file part first, and use PCHs merge adjacent strings maybe add a format string reduction pass that eliminates a format specifier and also the corresponding argument write some documentation about creating a c-vise pass: side effects, directory restrictions, etc. Konstantin suggestion: deal with un-preprocessed code in a smart way, for example by incrementally preprocessing files from inside c-vise implement suggestion from Joerg Sonnenberger: do transformations in chunks, like the line-reducer pass already does requires a good model of when this will be profitable -------------------------------------------------------------------- clang_delta TODO list: keep working to eliminate template stuff replace for-loops with expressions guessed from initializers guess that it executes 0 and 1 times change operators to other operators, e.g., replace / with + - From Konstantin Tokarev As you may know, there is a clang-based tool "Include What You Use" [1]. I think similar approach could be useful in C-Vise to remove whole header files instead of separate lines. Though I'm not sure it's feasible without non-preprocessed source file and compilation command line available. I can imagine the next algorithm of reduction: 1. Reduce only the last section of translation unit corresponding to original source file without #includes using all available passes. 2. Try to remove sections corresponding to "unused" headers 3. Move to section N-1 and proceed. Assuming that "interesting" fragment of code is located in sections with big numbers (source file and local headers) while first sections contain library headers, this approach might be more efficient than traditional line-based reduction. [1] http://code.google.com/p/include-what-you-use - (low priority) format string reductions: * remove anything that's not a %d or whatever from the format string * remove a %d directive and also the corresponding argument from a printf - (low priority) constant-propagation - (low priority) replace peephole passes in c_vise -------------------------------------------------------------------- cvise-2.3.0/clang_delta/000077500000000000000000000000001402162750500150645ustar00rootroot00000000000000cvise-2.3.0/clang_delta/.gitignore000066400000000000000000000001571402162750500170570ustar00rootroot00000000000000# Additions to the patterns specified in the root `.gitignore' file. # Files made by compilation. clang_delta cvise-2.3.0/clang_delta/AggregateToScalar.cpp000066400000000000000000000214531402162750500211140ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "AggregateToScalar.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Replace accesses to an aggregate member with \ a corresponding scalar variable. \ In more detail, the transformation creates \ a scalar variable for an aggregate access, \ assigns the initial value of the aggregate member to \ the scalar, and substitutes all accesses to the same aggregate \ member with the accesses to the corresponding scalar variable. \ (Note that this transformation is unsound).\n"; static RegisterTransformation Trans("aggregate-to-scalar", DescriptionMsg); class ATSCollectionVisitor : public RecursiveASTVisitor { public: explicit ATSCollectionVisitor(AggregateToScalar *Instance) : ConsumerInstance(Instance) { } bool VisitMemberExpr(MemberExpr *ME); bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); bool VisitDeclStmt(DeclStmt *DS); private: AggregateToScalar *ConsumerInstance; }; bool ATSCollectionVisitor::VisitMemberExpr(MemberExpr *ME) { if (ConsumerInstance->isInIncludedFile(ME)) return true; ValueDecl *OrigDecl = ME->getMemberDecl(); FieldDecl *FD = dyn_cast(OrigDecl); if (!FD) { // in C++, getMemberDecl returns a CXXMethodDecl. if (TransformationManager::isCXXLangOpt()) return true; TransAssert(0 && "Bad FD!\n"); } const Type *T = FD->getType().getTypePtr(); if (!T->isScalarType()) return true; RecordDecl *RD = FD->getParent(); TransAssert(RD && "NULL RecordDecl!"); if (!RD->isStruct() && !RD->isUnion()) return true; ConsumerInstance->addOneExpr(ME); return true; } bool ATSCollectionVisitor::VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) { if (ConsumerInstance->isInIncludedFile(ASE)) return true; const Type *T = ASE->getType().getTypePtr(); if (!T->isScalarType()) return true; ConsumerInstance->addOneExpr(ASE); return true; } bool ATSCollectionVisitor::VisitDeclStmt(DeclStmt *DS) { for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { VarDecl *CurrDecl = dyn_cast(*I); if (CurrDecl) ConsumerInstance->VarDeclToDeclStmtMap[CurrDecl] = DS; } return true; } void AggregateToScalar::Initialize(ASTContext &context) { Transformation::Initialize(context); AggregateAccessVisitor = new ATSCollectionVisitor(this); } bool AggregateToScalar::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { AggregateAccessVisitor->TraverseDecl(*I); } return true; } void AggregateToScalar::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheVarDecl && "NULL TheVarDecl!"); TransAssert(TheIdx && "NULL TheIdx!"); doRewrite(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool AggregateToScalar::addTmpVar(const Expr *RefE, const std::string &VarName, const std::string *InitStr) { std::string VarStr(VarName); QualType QT = RefE->getType(); QT.getAsStringInternal(VarStr, Context->getPrintingPolicy()); if (InitStr) { VarStr += " = "; VarStr += (*InitStr); } VarStr += ";"; if (TheVarDecl->getStorageClass() == SC_Static) VarStr = "static " + VarStr; TransAssert(!dyn_cast(TheVarDecl) && "We don't handle ParmVarDecl!"); if (TheVarDecl->isLocalVarDecl()) { DeclStmt *TheDeclStmt = VarDeclToDeclStmtMap[TheVarDecl]; TransAssert(TheDeclStmt && "NULL TheDeclStmt"); return RewriteHelper->addStringAfterStmt(TheDeclStmt, VarStr); } else { return RewriteHelper->addStringAfterVarDecl(TheVarDecl, VarStr); } } void AggregateToScalar::createNewVarName(std::string &VarName) { std::stringstream SS; SS << TheVarDecl->getNameAsString(); for (IndexVector::const_reverse_iterator I = TheIdx->rbegin(), E = TheIdx->rend(); I != E; ++I) { SS << "_" << (*I); } VarName = SS.str(); } bool AggregateToScalar::createNewVar(const Expr *RefE, std::string &VarName) { const Type *VarT = TheVarDecl->getType().getTypePtr(); TransAssert((VarT->isStructureType() || VarT->isUnionType() || VarT->isArrayType() || VarT->isPointerType()) && "Non-valid var type!"); createNewVarName(VarName); if (VarT->isPointerType()) return addTmpVar(RefE, VarName, NULL); const Expr *IE = TheVarDecl->getAnyInitializer(); if (!IE) return addTmpVar(RefE, VarName, NULL); const InitListExpr *ILE = dyn_cast(IE); if (!ILE) { return addTmpVar(RefE, VarName, NULL); } const Expr *InitE = getInitExprByIndex(*TheIdx, ILE); // We might have incomplete initialization list if (!InitE) return addTmpVar(RefE, VarName, NULL); std::string InitStr; if (InitE->getBeginLoc().isInvalid()) { const Type *ET = InitE->getType().getTypePtr(); if (ET->isIntegerType() || ET->isPointerType()) InitStr = "0"; else return addTmpVar(RefE, VarName, NULL); } else { RewriteHelper->getExprString(InitE, InitStr); } return addTmpVar(RefE, VarName, &InitStr); } void AggregateToScalar::doRewrite(void) { ExprSet *TheExprSet = ValidExprs[TheIdx]; TransAssert(!TheExprSet->empty() && "TheExprSet cannot be empty!"); ExprSet::iterator I = TheExprSet->begin(), E = TheExprSet->end(); std::string VarName(""); createNewVar(*I, VarName); for (; I != E; ++I) { RewriteHelper->replaceExpr((*I), VarName); } } void AggregateToScalar::addOneIdx(const Expr *E, const VarDecl *VD, IdxVectorSet *IdxSet, IndexVector *Idx) { IdxSet->insert(Idx); ExprSet *ESet = new ExprSet(); ValidExprs[Idx] = ESet; ESet->insert(E); ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheVarDecl = VD; TheIdx = Idx; } } bool AggregateToScalar::isStructuralEqualVectors(IndexVector *IV1, IndexVector *IV2) { unsigned int Sz = IV1->size(); if (Sz != IV2->size()) return false; for (unsigned int I = 0; I < Sz; ++I) { unsigned int Idx1 = (*IV1)[I]; unsigned int Idx2 = (*IV2)[I]; if (Idx1 != Idx2) return false; } return true; } void AggregateToScalar::addOneExpr(const Expr *Exp) { IndexVector *Idx = new IndexVector(); const Expr *BaseE = getBaseExprAndIdxs(Exp, *Idx); TransAssert(BaseE && "Invalid Base Expr for ArraySubscriptExpr!"); const DeclRefExpr *DRE = dyn_cast(BaseE); if (!DRE) { delete Idx; return; } const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) { delete Idx; return; } if (dyn_cast(VD)) { delete Idx; return; } const Type *VarT = VD->getType().getTypePtr(); if (!VarT->isStructureType() && !VarT->isUnionType() && !VarT->isArrayType() && !VarT->isPointerType()) { delete Idx; return; } const VarDecl *CanonicalDecl = VD->getCanonicalDecl(); IdxVectorSet *IdxSet = ValidVars[CanonicalDecl]; if (!IdxSet) { IdxSet = new IdxVectorSet(); ValidVars[VD] = IdxSet; addOneIdx(Exp, VD, IdxSet, Idx); return; } IndexVector *CachedIdx = NULL; for (IdxVectorSet::iterator I = IdxSet->begin(), E = IdxSet->end(); I != E; ++I) { if (isStructuralEqualVectors(*I, Idx)) { CachedIdx = (*I); break; } } if (!CachedIdx) { addOneIdx(Exp, VD, IdxSet, Idx); return; } ExprSet *CachedESet = ValidExprs[CachedIdx]; TransAssert(CachedESet && "NULL CachedESet!"); CachedESet->insert(Exp); delete Idx; } AggregateToScalar::~AggregateToScalar(void) { delete AggregateAccessVisitor; for (VarToIdx::iterator I = ValidVars.begin(), E = ValidVars.end(); I != E; ++I) { delete (*I).second; } for (IdxToExpr::iterator I = ValidExprs.begin(), E = ValidExprs.end(); I != E; ++I) { delete (*I).first; delete (*I).second; } } cvise-2.3.0/clang_delta/AggregateToScalar.h000066400000000000000000000046261402162750500205640ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef AGGREGATE_TO_SCALAR_H #define AGGREGATE_TO_SCALAR_H #include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class MemberExpr; class VarDecl; class InitListExpr; class DeclStmt; class Expr; class ArraySubscriptExpr; } class ATSCollectionVisitor; class AggregateToScalar : public Transformation { friend class ATSCollectionVisitor; public: AggregateToScalar(const char *TransName, const char *Desc) : Transformation(TransName, Desc), AggregateAccessVisitor(NULL), TheVarDecl(NULL), TheIdx(NULL) { } ~AggregateToScalar(void); private: typedef std::set ExprSet; typedef llvm::DenseMap IdxToExpr; typedef llvm::SmallPtrSet IdxVectorSet; typedef llvm::DenseMap VarToIdx; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isStructuralEqualVectors(IndexVector *IV1, IndexVector *IV2); void addOneIdx(const clang::Expr *E, const clang::VarDecl *VD, IdxVectorSet *IdxSet, IndexVector *Idx); void addOneExpr(const clang::Expr *E); bool createNewVar(const clang::Expr *RefE, std::string &VarName); bool addTmpVar(const clang::Expr *RefE, const std::string &VarName, const std::string *InitStr); void createNewVarName(std::string &VarName); void doRewrite(void); llvm::DenseMap VarDeclToDeclStmtMap; VarToIdx ValidVars; IdxToExpr ValidExprs; ATSCollectionVisitor *AggregateAccessVisitor; const clang::VarDecl *TheVarDecl; IndexVector *TheIdx; // Unimplemented AggregateToScalar(void); AggregateToScalar(const AggregateToScalar &); void operator=(const AggregateToScalar &); }; #endif cvise-2.3.0/clang_delta/BinOpSimplification.cpp000066400000000000000000000121441402162750500214740ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "BinOpSimplification.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "CommonStatementVisitor.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Simplify a complex binary expression to simple ones. \ For example, x = a + (b + c) will be transformed to \ tmp = b + c; x = a + tmp \n"; static RegisterTransformation Trans("binop-simplification", DescriptionMsg); class BSCollectionVisitor : public RecursiveASTVisitor { public: explicit BSCollectionVisitor(BinOpSimplification *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: BinOpSimplification *ConsumerInstance; }; class BSStatementVisitor : public CommonStatementVisitor { public: explicit BSStatementVisitor(BinOpSimplification *Instance) : ConsumerInstance(Instance) { } bool VisitBinaryOperator(BinaryOperator *BinOp); private: void handleSubExpr(Expr *E); BinOpSimplification *ConsumerInstance; }; bool BSCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || !FD->isThisDeclarationADefinition()) return true; ConsumerInstance->StmtVisitor->setCurrentFunctionDecl(FD); ConsumerInstance->StmtVisitor->TraverseDecl(FD); ConsumerInstance->StmtVisitor->setCurrentFunctionDecl(NULL); return true; } void BSStatementVisitor::handleSubExpr(Expr *E) { BinaryOperator *BinOp = dyn_cast(E->IgnoreParenCasts()); if (!BinOp) return; TransAssert(std::find(ConsumerInstance->ValidBinOps.begin(), ConsumerInstance->ValidBinOps.end(), BinOp) == ConsumerInstance->ValidBinOps.end()); ConsumerInstance->ValidBinOps.push_back(BinOp); ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheFuncDecl = CurrentFuncDecl; ConsumerInstance->TheStmt = CurrentStmt; ConsumerInstance->TheBinOp = BinOp; ConsumerInstance->NeedParen = NeedParen; } TraverseStmt(BinOp); } bool BSStatementVisitor::VisitBinaryOperator(BinaryOperator *BinOp) { if (BinOp->isAssignmentOp() && !BinOp->isCompoundAssignmentOp()) { Expr *RHS = BinOp->getRHS(); return TraverseStmt(RHS); } Expr *LHS = BinOp->getLHS(); handleSubExpr(LHS); Expr *RHS = BinOp->getRHS(); handleSubExpr(RHS); return false; } void BinOpSimplification::Initialize(ASTContext &context) { Transformation::Initialize(context); BinOpCollectionVisitor = new BSCollectionVisitor(this); StmtVisitor = new BSStatementVisitor(this); NameQueryWrap = new TransNameQueryWrap(RewriteHelper->getTmpVarNamePrefix()); } bool BinOpSimplification::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { BinOpCollectionVisitor->TraverseDecl(*I); } return true; } void BinOpSimplification::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransAssert(TheStmt && "NULL TheStmt!"); TransAssert(TheBinOp && "NULL TheBinOp"); NameQueryWrap->TraverseDecl(Ctx.getTranslationUnitDecl()); addNewTmpVariable(); addNewAssignStmt(); replaceBinOp(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool BinOpSimplification::addNewTmpVariable(void) { QualType QT = TheBinOp->getType(); std::string VarStr; std::stringstream SS; unsigned int NamePostfix = NameQueryWrap->getMaxNamePostfix(); SS << RewriteHelper->getTmpVarNamePrefix() << (NamePostfix + 1); VarStr = SS.str(); setTmpVarName(VarStr); QT.getAsStringInternal(VarStr, Context->getPrintingPolicy()); VarStr += ";"; return RewriteHelper->addLocalVarToFunc(VarStr, TheFuncDecl); } bool BinOpSimplification::addNewAssignStmt(void) { return RewriteHelper->addNewAssignStmtBefore(TheStmt, getTmpVarName(), TheBinOp, NeedParen); } bool BinOpSimplification::replaceBinOp(void) { return RewriteHelper->replaceExpr(TheBinOp, TmpVarName); } BinOpSimplification::~BinOpSimplification(void) { delete BinOpCollectionVisitor; delete StmtVisitor; delete NameQueryWrap; } cvise-2.3.0/clang_delta/BinOpSimplification.h000066400000000000000000000040121402162750500211340ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef BINOP_SIMPLIFICATION_H #define BINOP_SIMPLIFICATION_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class Stmt; class BinaryOperator; } class BSCollectionVisitor; class BSStatementVisitor; class BinOpSimplification : public Transformation { friend class BSCollectionVisitor; friend class BSStatementVisitor; public: BinOpSimplification(const char *TransName, const char *Desc) : Transformation(TransName, Desc), BinOpCollectionVisitor(NULL), StmtVisitor(NULL), NameQueryWrap(NULL), TheFuncDecl(NULL), TheStmt(NULL), TheBinOp(NULL), TmpVarName(""), NeedParen(false) { } ~BinOpSimplification(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool addNewTmpVariable(void); bool addNewAssignStmt(void); bool replaceBinOp(void); void setTmpVarName(std::string &Name) { TmpVarName = Name; } std::string getTmpVarName(void) { return TmpVarName; } clang::SmallVector ValidBinOps; BSCollectionVisitor *BinOpCollectionVisitor; BSStatementVisitor *StmtVisitor; TransNameQueryWrap *NameQueryWrap; clang::FunctionDecl *TheFuncDecl; clang::Stmt *TheStmt; clang::BinaryOperator *TheBinOp; std::string TmpVarName; bool NeedParen; // Unimplemented BinOpSimplification(void); BinOpSimplification(const BinOpSimplification &); void operator=(const BinOpSimplification &); }; #endif cvise-2.3.0/clang_delta/CMakeLists.txt000066400000000000000000000544071402162750500176360ustar00rootroot00000000000000## -*- mode: CMake -*- ## ## Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah ## All rights reserved. ## ## This file is distributed under the University of Illinois Open Source ## License. See the file COPYING for details. ############################################################################### cmake_minimum_required(VERSION 2.8.12) project(clang_delta) ############################################################################### # find_package(LLVM) is done by the topmost "CMakeLists.txt" file. # find_package(Clang) is done by the topmost "CMakeLists.txt" file. # Generate file "git_version.cpp". # configure_file("git_version.cpp.in" "git_version.cpp" @ONLY) function(configure_one_file path) configure_file( "${clang_delta_SOURCE_DIR}/${path}" "${clang_delta_BINARY_DIR}/${path}" COPYONLY ) endfunction(configure_one_file) set(SOURCE_FILES "/tests/test_clang_delta.py" "/tests/aggregate-to-scalar/cast.c" "/tests/aggregate-to-scalar/cast.output" "/tests/aggregate-to-scalar/test1.c" "/tests/aggregate-to-scalar/test1.output" "/tests/aggregate-to-scalar/test2.c" "/tests/aggregate-to-scalar/test2.output" "/tests/aggregate-to-scalar/test3.c" "/tests/aggregate-to-scalar/test3.output" "/tests/aggregate-to-scalar/test4.c" "/tests/aggregate-to-scalar/test4.output" "/tests/aggregate-to-scalar/test5.cc" "/tests/aggregate-to-scalar/test5.output" "/tests/aggregate-to-scalar/test6.cc" "/tests/aggregate-to-scalar/test6.output" "/tests/callexpr-to-value/macro1.c" "/tests/callexpr-to-value/macro1.output" "/tests/callexpr-to-value/macro2.c" "/tests/callexpr-to-value/macro2.output" "/tests/callexpr-to-value/test1.c" "/tests/callexpr-to-value/test1.output" "/tests/callexpr-to-value/test2.c" "/tests/callexpr-to-value/test2.output" "/tests/copy-propagation/copy1.cpp" "/tests/copy-propagation/copy1.output" "/tests/copy-propagation/copy2.cpp" "/tests/copy-propagation/copy2.output" "/tests/empty-struct-to-int/empty-struct.cpp" "/tests/empty-struct-to-int/empty-struct.output" "/tests/empty-struct-to-int/empty-struct2.cpp" "/tests/empty-struct-to-int/empty-struct2.output" "/tests/empty-struct-to-int/empty-struct3.cpp" "/tests/empty-struct-to-int/empty-struct3.output" "/tests/empty-struct-to-int/empty-struct4.cpp" "/tests/empty-struct-to-int/empty-struct4.output" "/tests/empty-struct-to-int/empty-struct5.cpp" "/tests/empty-struct-to-int/empty-struct5.output" "/tests/empty-struct-to-int/empty-struct6.c" "/tests/empty-struct-to-int/empty-struct6.output" "/tests/empty-struct-to-int/empty-struct7.c" "/tests/empty-struct-to-int/empty-struct7.output" "/tests/empty-struct-to-int/struct_int.c" "/tests/empty-struct-to-int/struct_int.output" "/tests/empty-struct-to-int/test1.cc" "/tests/empty-struct-to-int/test1.output" "/tests/empty-struct-to-int/test2.cc" "/tests/empty-struct-to-int/test2.output" "/tests/empty-struct-to-int/test3.c" "/tests/empty-struct-to-int/test3.output" "/tests/instantiate-template-param/default_param.cc" "/tests/instantiate-template-param/default_param.output" "/tests/instantiate-template-param/test1.cc" "/tests/instantiate-template-param/test1.output" "/tests/instantiate-template-param/test2.cc" "/tests/instantiate-template-param/test2.output" "/tests/instantiate-template-param/test3.cc" "/tests/local-to-global/macro.c" "/tests/local-to-global/macro.output" "/tests/local-to-global/unnamed_1.c" "/tests/local-to-global/unnamed_1.output" "/tests/local-to-global/unnamed_2.c" "/tests/local-to-global/unnamed_2.output" "/tests/local-to-global/unnamed_3.c" "/tests/local-to-global/unnamed_3.output" "/tests/param-to-global/macro.c" "/tests/param-to-global/macro.output" "/tests/reduce-array-dim/non-type-temp-arg.cpp" "/tests/reduce-array-dim/non-type-temp-arg.output" "/tests/reduce-pointer-level/scalar-init-expr.cpp" "/tests/reduce-pointer-level/scalar-init-expr.output" "/tests/remove-namespace/macro.cpp" "/tests/remove-namespace/macro.output" "/tests/remove-namespace/macro.output2" "/tests/remove-namespace/macro.output3" "/tests/remove-namespace/macro.output4" "/tests/remove-namespace/macro.output5" "/tests/remove-namespace/namespace.cpp" "/tests/remove-namespace/namespace.output" "/tests/remove-namespace/namespace.output2" "/tests/remove-namespace/namespace.output3" "/tests/remove-namespace/namespace2.cpp" "/tests/remove-namespace/namespace2.output" "/tests/remove-namespace/namespace2.output2" "/tests/remove-namespace/namespace3.cpp" "/tests/remove-namespace/namespace3.output" "/tests/remove-namespace/namespace3.output2" "/tests/remove-namespace/namespace3.output3" "/tests/remove-namespace/namespace4.cpp" "/tests/remove-namespace/namespace4.output" "/tests/remove-namespace/namespace5.cpp" "/tests/remove-namespace/namespace5.output" "/tests/remove-namespace/namespace5.output2" "/tests/remove-namespace/namespace5.output3" "/tests/remove-namespace/namespace5.output4" "/tests/remove-namespace/namespace6.cpp" "/tests/remove-namespace/namespace6.output" "/tests/remove-namespace/namespace6.output2" "/tests/remove-namespace/namespace7.cpp" "/tests/remove-namespace/namespace7.output" "/tests/remove-namespace/namespace7.output2" "/tests/remove-namespace/namespace7.output3" "/tests/remove-namespace/namespace8.cpp" "/tests/remove-namespace/namespace8.output" "/tests/remove-namespace/namespace8.output2" "/tests/remove-namespace/namespace9.cpp" "/tests/remove-namespace/namespace9.output" "/tests/remove-namespace/namespace10.cpp" "/tests/remove-namespace/namespace10.output" "/tests/remove-namespace/namespace10.output2" "/tests/remove-namespace/namespace11.cpp" "/tests/remove-namespace/namespace11.output" "/tests/remove-namespace/namespace11.output2" "/tests/remove-namespace/namespace12.cpp" "/tests/remove-namespace/namespace12.output" "/tests/remove-namespace/namespace12.output2" "/tests/remove-namespace/namespace12.output3" "/tests/remove-namespace/namespace13.cpp" "/tests/remove-namespace/namespace13.output" "/tests/remove-namespace/namespace13.output2" "/tests/remove-namespace/namespace14.cpp" "/tests/remove-namespace/namespace14.output" "/tests/remove-namespace/namespace15.cpp" "/tests/remove-namespace/namespace15.output" "/tests/remove-namespace/namespace15.output2" "/tests/remove-namespace/namespace15.output3" "/tests/remove-enum-member-value/builtin_macro.c" "/tests/remove-enum-member-value/builtin_macro.output" "/tests/remove-unused-enum-member/range.c" "/tests/remove-unused-enum-member/range.output" "/tests/remove-nested-function/remove_nested_func1.cc" "/tests/remove-nested-function/remove_nested_func1.output" "/tests/remove-try-catch/try-catch-1.cpp" "/tests/remove-try-catch/try-catch-1.output" "/tests/remove-try-catch/try-catch-2.cpp" "/tests/remove-try-catch/try-catch-2.output" "/tests/remove-unused-field/designated1.c" "/tests/remove-unused-field/designated1.output" "/tests/remove-unused-field/designated2.c" "/tests/remove-unused-field/designated2.output" "/tests/remove-unused-field/designated3.c" "/tests/remove-unused-field/designated3.output" "/tests/remove-unused-field/designated4.c" "/tests/remove-unused-field/designated4.output" "/tests/remove-unused-field/designated5.c" "/tests/remove-unused-field/designated5.output" "/tests/remove-unused-field/unused_field1.c" "/tests/remove-unused-field/unused_field1.output" "/tests/remove-unused-field/unused_field2.c" "/tests/remove-unused-field/unused_field2.output" "/tests/remove-unused-field/unused_field3.cpp" "/tests/remove-unused-field/unused_field3.output" "/tests/remove-unused-function/class.cc" "/tests/remove-unused-function/class.output" "/tests/remove-unused-function/const.cc" "/tests/remove-unused-function/const.output" "/tests/remove-unused-function/const.output2" "/tests/remove-unused-function/default.cc" "/tests/remove-unused-function/default.output" "/tests/remove-unused-function/default.output2" "/tests/remove-unused-function/delete.cc" "/tests/remove-unused-function/delete.output" "/tests/remove-unused-function/delete2.cc" "/tests/remove-unused-function/delete2.output" "/tests/remove-unused-function/delete2.output2" "/tests/remove-unused-function/delete2.output3" "/tests/remove-unused-function/delete2.output4" "/tests/remove-unused-function/inline_ns.cc" "/tests/remove-unused-function/inline_ns.output" "/tests/remove-unused-function/macro1.cc" "/tests/remove-unused-function/macro1.output" "/tests/remove-unused-function/macro2.cc" "/tests/remove-unused-function/macro2.output" "/tests/remove-unused-function/macro3.cc" "/tests/remove-unused-function/macro3.output" "/tests/remove-unused-function/template1.cc" "/tests/remove-unused-function/template1.output" "/tests/remove-unused-function/template2.cc" "/tests/remove-unused-function/template2.output" "/tests/remove-unused-function/unused-funcs.cc" "/tests/remove-unused-function/unused-funcs.output" "/tests/remove-unused-var/struct1.c" "/tests/remove-unused-var/struct1.output" "/tests/remove-unused-var/struct2.c" "/tests/remove-unused-var/struct2.output" "/tests/remove-unused-var/unused_var.cpp" "/tests/remove-unused-var/unused_var.output" "/tests/rename-class/base_specifier.cpp" "/tests/rename-class/base_specifier.output" "/tests/rename-class/bool.cc" "/tests/rename-class/bool.output" "/tests/rename-class/class_template.cc" "/tests/rename-class/class_template.output" "/tests/rename-class/class_template2.cc" "/tests/rename-class/class_template2.output" "/tests/rename-class/dependent.cpp" "/tests/rename-class/dependent.output" "/tests/rename-class/dependent_name.cpp" "/tests/rename-class/dependent_name.output" "/tests/rename-class/derive.cc" "/tests/rename-class/derive.output" "/tests/rename-class/dtor.cc" "/tests/rename-class/dtor.output" "/tests/rename-class/dtor1.cc" "/tests/rename-class/dtor1.output" "/tests/rename-class/elaborated_type1.cpp" "/tests/rename-class/elaborated_type1.output" "/tests/rename-class/elaborated_type2.cpp" "/tests/rename-class/elaborated_type2.output" "/tests/rename-class/explicit_specialization.cpp" "/tests/rename-class/explicit_specialization.output" "/tests/rename-class/forward_decl.cc" "/tests/rename-class/forward_decl.output" "/tests/rename-class/injected_name.cpp" "/tests/rename-class/injected_name.output" "/tests/rename-class/instantiation.cpp" "/tests/rename-class/instantiation.output" "/tests/rename-class/parm.cpp" "/tests/rename-class/parm.output" "/tests/rename-class/partial_specialization.cpp" "/tests/rename-class/partial_specialization.output" "/tests/rename-class/rename-class1.cpp" "/tests/rename-class/rename-class1.output" "/tests/rename-class/rename-class2.cpp" "/tests/rename-class/rename-class2.output" "/tests/rename-class/specialization.cpp" "/tests/rename-class/specialization.output" "/tests/rename-class/static_member.cc" "/tests/rename-class/static_member.output" "/tests/rename-class/template_class_1.cpp" "/tests/rename-class/template_class_1.output" "/tests/rename-class/template_parm.cpp" "/tests/rename-class/template_parm.output" "/tests/rename-class/template_template.cpp" "/tests/rename-class/template_template.output" "/tests/rename-class/template_template_parm.cpp" "/tests/rename-class/template_template_parm.output" "/tests/rename-class/typedef.cpp" "/tests/rename-class/typedef.output" "/tests/rename-class/typedef2.cc" "/tests/rename-class/typedef2.output" "/tests/rename-class/using.cpp" "/tests/rename-class/using.output" "/tests/rename-class/using1.cc" "/tests/rename-class/using1.output" "/tests/rename-cxx-method/overloaded.cc" "/tests/rename-cxx-method/overloaded.output" "/tests/rename-cxx-method/test1.cc" "/tests/rename-cxx-method/test1.output" "/tests/rename-cxx-method/test2.cc" "/tests/rename-cxx-method/test2.output" "/tests/rename-cxx-method/test3.cc" "/tests/rename-cxx-method/test3.output" "/tests/rename-fun/func_templ.cc" "/tests/rename-fun/func_templ.output" "/tests/rename-fun/overloaded.cc" "/tests/rename-fun/overloaded.output" "/tests/rename-fun/test1.c" "/tests/rename-fun/test1.output" "/tests/rename-fun/multi.c" "/tests/rename-fun/multi.output" "/tests/rename-param/invalid.c" "/tests/rename-param/invalid.output" "/tests/rename-param/stuck.ii" "/tests/rename-var/rename-var.c" "/tests/rename-var/rename-var.output" "/tests/replace-derived-class/replace-derived1.cpp" "/tests/replace-derived-class/replace-derived1.output" "/tests/replace-derived-class/replace-derived2.cpp" "/tests/replace-derived-class/replace-derived2.output" "/tests/replace-derived-class/replace-derived3.cpp" "/tests/replace-derived-class/replace-derived3.output" "/tests/replace-derived-class/replace-derived4.cpp" "/tests/replace-derived-class/replace-derived4.output" "/tests/replace-function-def-with-decl/macro1.c" "/tests/replace-function-def-with-decl/macro1.output" "/tests/replace-function-def-with-decl/macro2.c" "/tests/replace-function-def-with-decl/macro2.output" "/tests/replace-function-def-with-decl/simple.cpp" "/tests/replace-function-def-with-decl/simple.cpp.preserve_foo.output" "/tests/replace-function-def-with-decl/simple.cpp.preserve_missing.output" "/tests/replace-function-def-with-decl/simple.cpp.preserve_quack.output" "/tests/return-void/test1.c" "/tests/return-void/test1.output" "/tests/return-void/test2.c" "/tests/return-void/test2.output" "/tests/return-void/test3.c" "/tests/return-void/test3.output" "/tests/return-void/test4.c" "/tests/return-void/test4.output" "/tests/return-void/test5.c" "/tests/return-void/test5.output" "/tests/return-void/test6.c" "/tests/return-void/test6.output" "/tests/return-void/test7.cc" "/tests/return-void/test7.output" "/tests/simplify-callexpr/macro.c" "/tests/simplify-callexpr/macro.output" "/tests/simplify-callexpr/test.c" "/tests/simplify-callexpr/test.output" "/tests/simplify-callexpr/test2.c" "/tests/simplify-callexpr/test2.output" "/tests/simplify-if/macro.c" "/tests/simplify-if/macro.output" "/tests/simplify-recursive-template-instantiation/test.cc" "/tests/simplify-recursive-template-instantiation/test.output" "/tests/template-arg-to-int/not_valid5.cc" "/tests/union-to-struct/union1.c" "/tests/union-to-struct/union1.output" "/tests/union-to-struct/union2.c" "/tests/union-to-struct/union2.output" "/tests/union-to-struct/union3.c" "/tests/union-to-struct/union3.output" ) foreach(file IN LISTS SOURCE_FILES) configure_one_file(${file}) endforeach() # Add flags for compiling against LLVM. # add_definitions(${LLVM_DEFINITIONS}) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:NDEBUG>) # include_directories(${PROJECT_BINARY_DIR}) --- if we generated .h files here include_directories(${CMAKE_BINARY_DIR}) include_directories(${PROJECT_SOURCE_DIR}) # needed for gen'ed .cpp files include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${CLANG_INCLUDE_DIRS}) # only works for LLVM post-4.0 link_directories(${LLVM_LIBRARY_DIRS}) # ENE: Note that LLVM_LIBS is unused. # # The CLANG_LIBS defined below depend on various LLVM libraries. When we do # `target_link_libraries(clang_delta ${CLANG_LIBS})`, CMake's automatic library # dependency tracking adds ("is expected to add") the necessary LLVM libraries # and other libraries to the link set without us doing anything special. # # There are reports that this automatic tracking does not always work. If this # is the case for you, you can try adding LLVM_LIBS to the invocation of # `target_link_libraries()` later in this file. There are reports that # sometimes this doesn't solve the problem, so caveat emptor. # # There are reports that including LLVM_LIBS in `target_link_libraries()`, when # it is not needed, can cause dynamic link errors when `clang_delta` is run # (multiply defined symbols). This is another reason why we don't include # LLVM_LIBS in the `target_link_libraries()` call by default. # llvm_map_components_to_libnames(LLVM_LIBS coverage irreader mcparser objcarcopts option passes profiledata support ) if (${LLVM_LINK_LLVM_DYLIB}) set(CLANG_LIBS clang-cpp LLVM ) else() set(CLANG_LIBS clangAST clangBasic clangFrontend clangParse clangLex clangRewrite ) endif() add_executable(clang_delta ${CMAKE_BINARY_DIR}/config.h AggregateToScalar.cpp AggregateToScalar.h BinOpSimplification.cpp BinOpSimplification.h CallExprToValue.cpp CallExprToValue.h ClangDelta.cpp ClassTemplateToClass.cpp ClassTemplateToClass.h CombineGlobalVarDecl.cpp CombineGlobalVarDecl.h CombineLocalVarDecl.cpp CombineLocalVarDecl.h CommonParameterRewriteVisitor.h CommonRenameClassRewriteVisitor.h CommonStatementVisitor.h CommonTemplateArgumentVisitor.h CopyPropagation.cpp CopyPropagation.h EmptyStructToInt.cpp EmptyStructToInt.h ExpressionDetector.cpp ExpressionDetector.h InstantiateTemplateParam.cpp InstantiateTemplateParam.h InstantiateTemplateTypeParamToInt.cpp InstantiateTemplateTypeParamToInt.h LiftAssignmentExpr.cpp LiftAssignmentExpr.h LocalToGlobal.cpp LocalToGlobal.h MoveFunctionBody.cpp MoveFunctionBody.h MoveGlobalVar.cpp MoveGlobalVar.h ParamToGlobal.cpp ParamToGlobal.h ParamToLocal.cpp ParamToLocal.h ReduceArrayDim.cpp ReduceArrayDim.h ReduceArraySize.cpp ReduceArraySize.h ReduceClassTemplateParameter.cpp ReduceClassTemplateParameter.h ReducePointerLevel.cpp ReducePointerLevel.h ReducePointerPairs.cpp ReducePointerPairs.h RemoveAddrTaken.cpp RemoveAddrTaken.h RemoveArray.cpp RemoveArray.h RemoveBaseClass.cpp RemoveBaseClass.h RemoveCtorInitializer.cpp RemoveCtorInitializer.h RemoveEnumMemberValue.cpp RemoveEnumMemberValue.h RemoveNamespace.cpp RemoveNamespace.h RemoveNestedFunction.cpp RemoveNestedFunction.h RemovePointer.cpp RemovePointer.h RemoveTrivialBaseTemplate.cpp RemoveTrivialBaseTemplate.h RemoveTryCatch.cpp RemoveTryCatch.h RemoveUnresolvedBase.cpp RemoveUnresolvedBase.h RemoveUnusedEnumMember.cpp RemoveUnusedEnumMember.h RemoveUnusedFunction.cpp RemoveUnusedFunction.h RemoveUnusedOuterClass.cpp RemoveUnusedOuterClass.h RemoveUnusedStructField.cpp RemoveUnusedStructField.h RemoveUnusedVar.cpp RemoveUnusedVar.h RenameCXXMethod.cpp RenameCXXMethod.h RenameClass.cpp RenameClass.h RenameFun.cpp RenameFun.h RenameParam.cpp RenameParam.h RenameVar.cpp RenameVar.h ReplaceArrayAccessWithIndex.cpp ReplaceArrayAccessWithIndex.h ReplaceArrayIndexVar.cpp ReplaceArrayIndexVar.h ReplaceCallExpr.cpp ReplaceCallExpr.h ReplaceClassWithBaseTemplateSpec.cpp ReplaceClassWithBaseTemplateSpec.h ReplaceDependentName.cpp ReplaceDependentName.h ReplaceDependentTypedef.cpp ReplaceDependentTypedef.h ReplaceDerivedClass.cpp ReplaceDerivedClass.h ReplaceFunctionDefWithDecl.cpp ReplaceFunctionDefWithDecl.h ReplaceOneLevelTypedefType.cpp ReplaceOneLevelTypedefType.h ReplaceSimpleTypedef.cpp ReplaceSimpleTypedef.h ReplaceUndefinedFunction.cpp ReplaceUndefinedFunction.h ReturnVoid.cpp ReturnVoid.h RewriteUtils.cpp RewriteUtils.h SimpleInliner.cpp SimpleInliner.h SimplifyCallExpr.cpp SimplifyCallExpr.h SimplifyCommaExpr.cpp SimplifyCommaExpr.h SimplifyDependentTypedef.cpp SimplifyDependentTypedef.h SimplifyIf.cpp SimplifyIf.h SimplifyNestedClass.cpp SimplifyNestedClass.h SimplifyRecursiveTemplateInstantiation.cpp SimplifyRecursiveTemplateInstantiation.h SimplifyStruct.cpp SimplifyStruct.h SimplifyStructUnionDecl.cpp SimplifyStructUnionDecl.h TemplateArgToInt.cpp TemplateArgToInt.h TemplateNonTypeArgToInt.cpp TemplateNonTypeArgToInt.h Transformation.cpp Transformation.h TransformationManager.cpp TransformationManager.h UnifyFunctionDecl.cpp UnifyFunctionDecl.h UnionToStruct.cpp UnionToStruct.h VectorToArray.cpp VectorToArray.h ${PROJECT_BINARY_DIR}/git_version.cpp git_version.h ) # ENE: See comment above about why LLVM_LIBS is not included in this call. target_link_libraries(clang_delta ${CLANG_LIBS}) # For cases in which the LLVM libraries are shared libraries, remember where # the shared libraries are. set_target_properties(clang_delta PROPERTIES BUILD_WITH_INSTALL_RPATH "yes" INSTALL_RPATH "${LLVM_LIBRARY_DIRS}" ) # On Windows, we also need to link with "Version.dll" system library. # See . if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") target_link_libraries(clang_delta Version) endif() # UndefinedBehaviourSanitizer set(CMAKE_C_FLAGS_UBSAN "-fsanitize=undefined -g" CACHE STRING "Flags used by the C compiler during UndefinedBehaviourSanitizer builds." FORCE) set(CMAKE_CXX_FLAGS_UBSAN "-fsanitize=undefined -g" CACHE STRING "Flags used by the C++ compiler during UndefinedBehaviourSanitizer builds." FORCE) # AddressSanitizer set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -g" CACHE STRING "Flags used by the C compiler during AddressSanitizer builds." FORCE) set(CMAKE_CXX_FLAGS_ASAN "-fsanitize=address -g" CACHE STRING "Flags used by the C++ compiler during AddressSanitizer builds." FORCE) # Coverage builds set(CMAKE_C_FLAGS_COVERAGE "--coverage" CACHE STRING "Flags used by the C compiler during coverage builds." FORCE) set(CMAKE_CXX_FLAGS_COVERAGE "--coverage" CACHE STRING "Flags used by the C++ compiler during coverage builds." FORCE) install(TARGETS clang_delta DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}/${cvise_PACKAGE}/" ) # If binary is read-only, then installing may fail with an error: # CMake Error at cmake_install.cmake:45 (FILE): # file RPATH_REMOVE could not remove RPATH from file: # /disk2/randtest/install/libexec/clang_delta # Error opening file for update. # # Do I want RPATH at all? We can turn it off, by setting CMAKE_SKIP_RPATH # https://cmake.org/cmake/help/v2.8.8/cmake.html#variable%3aCMAKE_SKIP_RPATH # See also the stuff about RPATH for `set_target_properties', which I don't # really grok: # https://cmake.org/cmake/help/v2.8.8/cmake.html#command:set_target_properties # # PERMISSIONS # OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ##### ############################################################################### ## End of file. cvise-2.3.0/clang_delta/CallExprToValue.cpp000066400000000000000000000074761402162750500206200ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "CallExprToValue.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Replace a call expression with a value or variable which \ has the same type as CallExpr's type. If CallExpr is type \ of integer/pointer, it will be replaced with 0. If it has \ type of union/struct, it will be replaced with a newly created \ global variable with a correct type. \n"; static RegisterTransformation Trans("callexpr-to-value", DescriptionMsg); class CallExprToValueVisitor : public RecursiveASTVisitor { public: explicit CallExprToValueVisitor(CallExprToValue *Instance) : ConsumerInstance(Instance), CurrentFD(NULL) { } bool VisitCallExpr(CallExpr *CE); bool VisitFunctionDecl(FunctionDecl *FD); private: CallExprToValue *ConsumerInstance; const FunctionDecl *CurrentFD; }; bool CallExprToValueVisitor::VisitCallExpr(CallExpr *CE) { if (ConsumerInstance->isInIncludedFile(CE)) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->TransformationCounter != ConsumerInstance->ValidInstanceNum) return true; ConsumerInstance->TheCallExpr = CE; ConsumerInstance->CurrentFD = CurrentFD; return true; } bool CallExprToValueVisitor::VisitFunctionDecl(FunctionDecl *FD) { // Note that CurrentFD could not be the function decl where TheCallExpr // shows up, e.g., we could have: // struct A { // void foo(); // static int value = bar(); // }; CurrentFD = FD; return true; } void CallExprToValue::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new CallExprToValueVisitor(this); NameQueryWrap = new TransNameQueryWrap(RewriteHelper->getTmpVarNamePrefix()); } void CallExprToValue::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheCallExpr && "NULL TheCallExpr!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); NameQueryWrap->TraverseDecl(Ctx.getTranslationUnitDecl()); NamePostfix = NameQueryWrap->getMaxNamePostfix() + 1; replaceCallExpr(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void CallExprToValue::replaceCallExpr(void) { std::string CommaStr = ""; QualType RVQualType = TheCallExpr->getType(); const Type *RVType = RVQualType.getTypePtr(); if (RVType->isVoidType()) { // Nothing to do } else if (RVType->isUnionType() || RVType->isStructureType()) { std::string RVStr(""); RewriteHelper->getTmpTransName(NamePostfix, RVStr); NamePostfix++; CommaStr = RVStr; RVQualType.getAsStringInternal(RVStr, Context->getPrintingPolicy()); RVStr += ";\n"; if (CurrentFD) { RewriteHelper->insertStringBeforeFunc(CurrentFD, RVStr); } else { TheRewriter.InsertTextBefore(TheCallExpr->getBeginLoc(), RVStr); } } else { CommaStr = "0"; } RewriteHelper->replaceExpr(TheCallExpr, CommaStr); } CallExprToValue::~CallExprToValue(void) { delete CollectionVisitor; delete NameQueryWrap; } cvise-2.3.0/clang_delta/CallExprToValue.h000066400000000000000000000027761402162750500202630ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef CALL_EXPR_TO_VALUE_H #define CALL_EXPR_TO_VALUE_H #include #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class CallExpr; class Expr; } class CallExprToValueVisitor; class CallExprToValue : public Transformation { friend class CallExprToValueVisitor; public: CallExprToValue(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), NameQueryWrap(NULL), TheCallExpr(NULL), CurrentFD(NULL), NamePostfix(0) { } ~CallExprToValue(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneArgStr(const clang::Expr *Arg, std::string &Str); void replaceCallExpr(void); CallExprToValueVisitor *CollectionVisitor; TransNameQueryWrap *NameQueryWrap; const clang::CallExpr *TheCallExpr; const clang::FunctionDecl *CurrentFD; unsigned int NamePostfix; // Unimplemented CallExprToValue(void); CallExprToValue(const CallExprToValue &); void operator=(const CallExprToValue &); }; #endif cvise-2.3.0/clang_delta/ClangDelta.cpp000066400000000000000000000176201402162750500175740ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include #include #include #include "llvm/Support/raw_ostream.h" #include "TransformationManager.h" #include "git_version.h" static TransformationManager *TransMgr; static int ErrorCode = -1; static void PrintVersion() { llvm::outs() << "clang_delta " << PACKAGE_VERSION << "\n"; llvm::outs() << "Git version: " << git_version << "\n"; // XXX print copyright, contact info, etc.? } static void PrintHelpMessage() { PrintVersion(); llvm::outs() << "\n"; llvm::outs() << "Usage: \n"; llvm::outs() << " clang_delta "; llvm::outs() << "--transformation= "; llvm::outs() << "--counter= "; llvm::outs() << "--output= "; llvm::outs() << "\n\n"; llvm::outs() << "clang_delta options:\n"; llvm::outs() << " --help: "; llvm::outs() << "print this message\n"; llvm::outs() << " --version: "; llvm::outs() << "print the program version number\n"; llvm::outs() << " --verbose-transformations: "; llvm::outs() << "print verbose description messages for all "; llvm::outs() << "transformations\n"; llvm::outs() << " --transformation=: "; llvm::outs() << "specify the transformation\n"; llvm::outs() << " --transformations: "; llvm::outs() << "print the names of all available transformations\n"; llvm::outs() << " --query-instances=: "; llvm::outs() << "query available transformation instances for a given "; llvm::outs() << "transformation\n"; llvm::outs() << " --counter=: "; llvm::outs() << "specify the instance of the transformation to perform\n"; llvm::outs() << " --to-counter=: "; llvm::outs() << "specify the ending instance of the transformation to "; llvm::outs() << "perform (when this option is given, clang_delta will "; llvm::outs() << "rewrite multiple instances [counter,to-counter] "; llvm::outs() << "simultaneously. Note that currently only "; llvm::outs() << "replace-function-def-with-decl supports this feature.)\n"; llvm::outs() << " --replacement=: "; llvm::outs() << "instead of performing normal rewriting, the candidate "; llvm::outs() << "pointed by the counter will be replaced by the passed "; llvm::outs() << "\"string\". Currently, this option works only with "; llvm::outs() << "transformation expression-detector.\n"; llvm::outs() << " --preserve-routine=: "; llvm::outs() << "only modify routines that do not match \"string\". "; llvm::outs() << "Note that currently only replace-function-def-with-decl"; llvm::outs() << "supports this feature.\n"; llvm::outs() << " --check-reference=: "; llvm::outs() << "insert code to check if the candidate designated by the "; llvm::outs() << "counter equals to the reference value or not. Currently, "; llvm::outs() << "this option works only with transformation "; llvm::outs() << "expression-detector.\n"; llvm::outs() << " --output=: "; llvm::outs() << "specify where to output the transformed source code "; llvm::outs() << "(default: stdout)\n"; llvm::outs() << " --std=: "; llvm::outs() << "specify C++ standard used (c++98, c++11, c++14, c++17, c++20) "; llvm::outs() << "\n"; llvm::outs() << " --report-instances-count: "; llvm::outs() << "report number of transformation instances on stderr "; llvm::outs() << "\n"; llvm::outs() << " --warn-on-counter-out-of-bounds: "; llvm::outs() << "make only warning when a counter is out of bounds "; llvm::outs() << "(replace-function-def-with-decl and remove-unused-function are supported)"; llvm::outs() << "\n"; } static void DieOnBadCmdArg(const std::string &ArgStr) { llvm::outs() << "Error: Bad command line option `" << ArgStr << "`\n"; llvm::outs() << "\n"; PrintHelpMessage(); TransformationManager::Finalize(); exit(-1); } static void Die(const std::string &Message) { llvm::outs() << "Error: " << Message << "\n"; TransformationManager::Finalize(); exit(ErrorCode); } static void HandleOneArgValue(const std::string &ArgValueStr, size_t SepPos) { if ((SepPos < 1) || (SepPos >= ArgValueStr.length())) { DieOnBadCmdArg("--" + ArgValueStr); } std::string ArgName, ArgValue; ArgName = ArgValueStr.substr(0, SepPos); ArgValue = ArgValueStr.substr(SepPos+1); if (!ArgName.compare("transformation")) { if (TransMgr->setTransformation(ArgValue)) { Die("Invalid transformation[" + ArgValue + "]"); } } else if (!ArgName.compare("query-instances")) { if (TransMgr->setTransformation(ArgValue)) { Die("Invalid transformation[" + ArgValue + "]"); } TransMgr->setQueryInstanceFlag(true); TransMgr->setTransformationCounter(1); } else if (!ArgName.compare("counter")) { int Val; std::stringstream TmpSS(ArgValue); if (!(TmpSS >> Val)) { ErrorCode = TransformationManager::ErrorInvalidCounter; Die("Invalid counter[" + ArgValueStr + "]"); } TransMgr->setTransformationCounter(Val); } else if (!ArgName.compare("to-counter")) { int Val; std::stringstream TmpSS(ArgValue); if (!(TmpSS >> Val)) { ErrorCode = TransformationManager::ErrorInvalidCounter; Die("Invalid to-counter[" + ArgValueStr + "]"); } TransMgr->setToCounter(Val); } else if (!ArgName.compare("output")) { TransMgr->setOutputFileName(ArgValue); } else if (!ArgName.compare("replacement")) { TransMgr->setReplacement(ArgValue); } else if (!ArgName.compare("preserve-routine")) { TransMgr->setPreserveRoutine(ArgValue); } else if (!ArgName.compare("check-reference")) { TransMgr->setReferenceValue(ArgValue); } else if (!ArgName.compare("std")) { TransMgr->setCXXStandard(ArgValue); } else { DieOnBadCmdArg("--" + ArgValueStr); } } static void HandleOneNoneValueArg(const std::string &ArgStr) { if (!ArgStr.compare("help")) { PrintHelpMessage(); exit(0); } else if (!ArgStr.compare("version")) { PrintVersion(); exit(0); } else if (!ArgStr.compare("transformations")) { TransMgr->printTransformationNames(); exit(0); } else if (!ArgStr.compare("verbose-transformations")) { TransMgr->printTransformations(); exit(0); } else if (!ArgStr.compare("report-instances-count")) { TransMgr->setReportInstancesCount(true); } else if (!ArgStr.compare("warn-on-counter-out-of-bounds")) { TransMgr->setWarnOnCounterOutOfBounds(true); } else { DieOnBadCmdArg(ArgStr); } } static void HandleOneArg(const char *Arg) { std::string ArgStr(Arg); if (!ArgStr.compare(0, 2, "--")) { std::string SubArgStr = ArgStr.substr(2); if (!SubArgStr.length()) DieOnBadCmdArg(ArgStr); size_t found; found = SubArgStr.find('='); if (found != std::string::npos) { HandleOneArgValue(SubArgStr, found); } else { HandleOneNoneValueArg(SubArgStr); } } else { TransMgr->setSrcFileName(ArgStr); } } int main(int argc, char **argv) { TransMgr = TransformationManager::GetInstance(); for (int i = 1; i < argc; i++) { HandleOneArg(argv[i]); } std::string ErrorMsg; if (!TransMgr->verify(ErrorMsg, ErrorCode)) Die(ErrorMsg); if (!TransMgr->initializeCompilerInstance(ErrorMsg)) Die(ErrorMsg); if (!TransMgr->doTransformation(ErrorMsg, ErrorCode)) { // fail to do transformation Die(ErrorMsg); } if (TransMgr->getQueryInstanceFlag()) TransMgr->outputNumTransformationInstances(); if (TransMgr->getReportInstancesCount()) TransMgr->outputNumTransformationInstancesToStderr(); TransformationManager::Finalize(); return 0; } cvise-2.3.0/clang_delta/ClassTemplateToClass.cpp000066400000000000000000000260271402162750500216310ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ClassTemplateToClass.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Change a class template to a class if this class template: \n\ * has only one parameter, and \n\ * the parameter is unused. \n"; static RegisterTransformation Trans("class-template-to-class", DescriptionMsg); class ClassTemplateToClassASTVisitor : public RecursiveASTVisitor { public: explicit ClassTemplateToClassASTVisitor(ClassTemplateToClass *Instance) : ConsumerInstance(Instance) { } bool VisitClassTemplateDecl(ClassTemplateDecl *D); private: ClassTemplateToClass *ConsumerInstance; }; class ClassTemplateToClassSpecializationTypeRewriteVisitor : public RecursiveASTVisitor { public: explicit ClassTemplateToClassSpecializationTypeRewriteVisitor( ClassTemplateToClass *Instance) : ConsumerInstance(Instance) { } bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc Loc); private: ClassTemplateToClass *ConsumerInstance; }; namespace { class TemplateParameterTypeVisitor : public RecursiveASTVisitor { public: typedef llvm::SmallPtrSet TypeParmDeclSet; typedef llvm::SmallPtrSet TemplateNameSet; ~TemplateParameterTypeVisitor(void) { for (TemplateNameSet::iterator I = TmplNames.begin(), E = TmplNames.end(); I != E; ++I) delete (*I); } explicit TemplateParameterTypeVisitor(ASTContext *Ctx) : Context(Ctx) { } bool VisitTemplateTypeParmType(TemplateTypeParmType *Ty); bool VisitTemplateSpecializationType(TemplateSpecializationType *Ty); bool isAUsedParameter(NamedDecl *ND); private: TypeParmDeclSet ParmDecls; TemplateNameSet TmplNames; ASTContext *Context; }; bool TemplateParameterTypeVisitor::VisitTemplateTypeParmType( TemplateTypeParmType *Ty) { TemplateTypeParmDecl *D = Ty->getDecl(); ParmDecls.insert(D); return true; } bool TemplateParameterTypeVisitor::VisitTemplateSpecializationType( TemplateSpecializationType *Ty) { TemplateName Name = Ty->getTemplateName(); if (Name.getKind() != TemplateName::Template) return true; TemplateName *NewName = new TemplateName(Name.getAsTemplateDecl()); TmplNames.insert(NewName); return true; } bool TemplateParameterTypeVisitor::isAUsedParameter(NamedDecl *ND) { if (TemplateTypeParmDecl *ParmD = dyn_cast(ND)) { return ParmDecls.count(ParmD); } if (TemplateTemplateParmDecl *ParmD = dyn_cast(ND)) { TemplateName Name(ParmD); for (TemplateNameSet::iterator I = TmplNames.begin(), E = TmplNames.end(); I != E; ++I) { if (Context->hasSameTemplateName(*(*I), Name)) return true; } return false; } TransAssert(0 && "Uncatched Template Parameter Kind!"); return false; } } bool ClassTemplateToClassASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (ConsumerInstance->isInIncludedFile(D)) return true; ClassTemplateDecl *CanonicalD = D->getCanonicalDecl(); if (ConsumerInstance->VisitedDecls.count(CanonicalD)) return true; ConsumerInstance->VisitedDecls.insert(CanonicalD); if (ConsumerInstance->isValidClassTemplateDecl(D)) { ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheClassTemplateDecl = CanonicalD; ConsumerInstance->TheTemplateName = new TemplateName(CanonicalD); } } return true; } bool ClassTemplateToClassSpecializationTypeRewriteVisitor:: VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc Loc) { const TemplateSpecializationType *Ty = dyn_cast(Loc.getTypePtr()); TransAssert(Ty && "Invalid TemplateSpecializationType!"); TemplateName TmplName = Ty->getTemplateName(); if (!ConsumerInstance->referToTheTemplateDecl(TmplName)) return true; SourceLocation TmplKeyLoc = Loc.getTemplateKeywordLoc(); if (TmplKeyLoc.isValid()) ConsumerInstance->TheRewriter.RemoveText(TmplKeyLoc, 8); // it's necessary to check the validity of locations, otherwise // we will get assertion errors... // note that some implicit typeloc has been visited by Clang, e.g. // template < typename > struct A { }; // struct B:A < int > { // B ( ) { } // }; // base initializer A is not presented in the code but visited, // so, we need to make sure locations are valid. SourceLocation LAngleLoc = Loc.getLAngleLoc(); if (LAngleLoc.isInvalid()) return true; SourceLocation RAngleLoc = Loc.getRAngleLoc(); if (RAngleLoc.isInvalid()) return true; ConsumerInstance->TheRewriter.RemoveText(SourceRange(LAngleLoc, RAngleLoc)); return true; } void ClassTemplateToClass::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ClassTemplateToClassASTVisitor(this); RewriteVisitor = new ClassTemplateToClassSpecializationTypeRewriteVisitor(this); } void ClassTemplateToClass::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheClassTemplateDecl && "NULL TheClassTemplateDecl!"); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); rewriteClassTemplateDecls(); rewriteClassTemplatePartialSpecs(); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ClassTemplateToClass::removeTemplateAndParameter(SourceLocation LocStart, const TemplateParameterList *TPList) { SourceLocation LocEnd = TPList->getRAngleLoc(); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); } void ClassTemplateToClass::rewriteClassTemplateDecls(void) { for (ClassTemplateDecl::redecl_iterator I = TheClassTemplateDecl->redecls_begin(), E = TheClassTemplateDecl->redecls_end(); I != E; ++I) { const TemplateParameterList *TPList = (*I)->getTemplateParameters(); SourceLocation LocStart = (*I)->getBeginLoc(); removeTemplateAndParameter(LocStart, TPList); } } void ClassTemplateToClass::rewriteClassTemplatePartialSpecs(void) { SmallVector PartialDecls; TheClassTemplateDecl->getPartialSpecializations(PartialDecls); for (SmallVector::iterator I = PartialDecls.begin(), E = PartialDecls.end(); I != E; ++I) { const ClassTemplatePartialSpecializationDecl *PartialD = (*I); removeTemplateAndParameter(PartialD->getSourceRange().getBegin(), PartialD->getTemplateParameters()); const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); TransAssert(ArgList && "Invalid ArgList!"); const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); TransAssert(ArgLocs && "Invalid ArcLogs!"); unsigned NumArgs = ArgList->NumTemplateArgs; TransAssert((NumArgs > 0) && "Invalid NumArgs!"); const TemplateArgumentLoc FirstArgLoc = ArgLocs[0]; SourceLocation StartLoc = FirstArgLoc.getSourceRange().getBegin(); const TemplateArgumentLoc LastArgLoc = ArgLocs[NumArgs - 1]; SourceRange LastRange = LastArgLoc.getSourceRange(); SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(LastRange, '>'); RewriteHelper->removeTextFromLeftAt(SourceRange(StartLoc, EndLoc), '<', EndLoc); } } bool ClassTemplateToClass::isUsedNamedDecl(NamedDecl *ND, Decl *D) { TemplateParameterTypeVisitor ParamVisitor(Context); ParamVisitor.TraverseDecl(D); return ParamVisitor.isAUsedParameter(ND); } bool ClassTemplateToClass::hasUsedNameDecl( ClassTemplatePartialSpecializationDecl *PartialD) { if (!PartialD->isCompleteDefinition()) return false; llvm::SmallPtrSet Params; TemplateParameterList *PartialTPList = PartialD->getTemplateParameters(); for (unsigned PI = 0; PI < PartialTPList->size(); ++PI) { NamedDecl *ND = PartialTPList->getParam(PI); if (dyn_cast(ND)) continue; Params.insert(ND); } TemplateParameterTypeVisitor ParamVisitor(Context); // Skip visiting parameters and arguments for (CXXRecordDecl::base_class_iterator I = PartialD->bases_begin(), E = PartialD->bases_end(); I != E; ++I) { ParamVisitor.TraverseType(I->getType()); } DeclContext *Ctx = dyn_cast(PartialD); for (DeclContext::decl_iterator DI = Ctx->decls_begin(), DE = Ctx->decls_end(); DI != DE; ++DI) { ParamVisitor.TraverseDecl(*DI); } for (llvm::SmallPtrSet::iterator I = Params.begin(), E = Params.end(); I != E; ++I) { if (ParamVisitor.isAUsedParameter(*I)) return true; } return false; } bool ClassTemplateToClass::isValidClassTemplateDecl(ClassTemplateDecl *TmplD) { TemplateParameterList *TPList = TmplD->getTemplateParameters(); if (TPList->size() != 1) return false; CXXRecordDecl *CXXRD = TmplD->getTemplatedDecl(); CXXRecordDecl *Def = CXXRD->getDefinition(); if (!Def) return true; NamedDecl *ND = TPList->getParam(0); if (dyn_cast(ND)) return true; if (isUsedNamedDecl(ND, Def)) return false; SmallVector PartialDecls; TmplD->getPartialSpecializations(PartialDecls); for (SmallVector::iterator I = PartialDecls.begin(), E = PartialDecls.end(); I != E; ++I) { if (hasUsedNameDecl(*I)) return false; } return true; } bool ClassTemplateToClass::referToTheTemplateDecl(TemplateName TmplName) { return Context->hasSameTemplateName(*TheTemplateName, TmplName); } ClassTemplateToClass::~ClassTemplateToClass(void) { delete TheTemplateName; delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ClassTemplateToClass.h000066400000000000000000000044521402162750500212740ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef CLASS_TEMPLATE_TO_CLASS_H #define CLASS_TEMPLATE_TO_CLASS_H #include "Transformation.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; class ClassTemplateDecl; class NamedDecl; class CXXRecordDecl; class ClassTemplatePartialSpecializationDecl; class TemplateParameterList; class TemplateName; } class ClassTemplateToClassASTVisitor; class ClassTemplateToClassSpecializationTypeRewriteVisitor; class ClassTemplateToClass : public Transformation { friend class ClassTemplateToClassASTVisitor; friend class ClassTemplateToClassSpecializationTypeRewriteVisitor; public: ClassTemplateToClass(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheClassTemplateDecl(NULL), TheTemplateName(NULL) {} ~ClassTemplateToClass(void); private: typedef llvm::SmallPtrSet ClassTemplateDeclSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isValidClassTemplateDecl(clang::ClassTemplateDecl *D); bool isUsedNamedDecl(clang::NamedDecl *ND, clang::Decl *Def); bool hasUsedNameDecl(clang::ClassTemplatePartialSpecializationDecl *PartialD); void removeTemplateAndParameter(clang::SourceLocation LocStart, const clang::TemplateParameterList *TPList); void rewriteClassTemplateDecls(void); void rewriteClassTemplatePartialSpecs(void); bool referToTheTemplateDecl(clang::TemplateName TmplName); ClassTemplateDeclSet VisitedDecls; ClassTemplateToClassASTVisitor *CollectionVisitor; ClassTemplateToClassSpecializationTypeRewriteVisitor *RewriteVisitor; clang::ClassTemplateDecl *TheClassTemplateDecl; clang::TemplateName *TheTemplateName; // Unimplemented ClassTemplateToClass(void); ClassTemplateToClass(const ClassTemplateToClass &); }; #endif cvise-2.3.0/clang_delta/CombineGlobalVarDecl.cpp000066400000000000000000000077261402162750500215420ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "CombineGlobalVarDecl.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Combine global variable declarations with the same type. \ Each iteration only does one combination, i.e., \ for the code below: \n\ int a, b; \n\ int c; \n\ int d; \n\ We will need to invoke this transformation twice \ to achieve a complete combination. \ This pass only combines declarations with exactly \ the same type, e.g., it won't combine int *x and int y,\ although it's valid we can have int *x, y in a DeclGroup. \ Note that this transformation always tries to combine \ the rest of declarations with the very first one, \ so it is an unsound transformation and could result \ in compilation failures. \n"; static RegisterTransformation Trans("combine-global-var", DescriptionMsg); void CombineGlobalVarDecl::Initialize(ASTContext &context) { Transformation::Initialize(context); } bool CombineGlobalVarDecl::HandleTopLevelDecl(DeclGroupRef DGR) { DeclGroupRef::iterator DI = DGR.begin(); VarDecl *VD = dyn_cast(*DI); if (!VD || isInIncludedFile(VD)) return true; SourceRange Range = VD->getSourceRange(); if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid()) return true; const Type *T = VD->getType().getTypePtr(); const Type *CanonicalT = Context->getCanonicalType(T); DeclGroupVector *DV; TypeToDeclMap::iterator TI = AllDeclGroups.find(CanonicalT); if (TI == AllDeclGroups.end()) { DV = new DeclGroupVector(); AllDeclGroups[CanonicalT] = DV; } else { ValidInstanceNum++; DV = (*TI).second; if (ValidInstanceNum == TransformationCounter) { if (DV->size() >= 1) { void* DP1 = *(DV->begin()); TheDeclGroupRefs.push_back(DP1); TheDeclGroupRefs.push_back(DGR.getAsOpaquePtr()); } } } // Note that it's unnecessary to keep all encountered // DeclGroupRefs. We could choose a light way similar // to what we implemented in CombineLocalVarDecl. // I kept the code here because I feel we probably // need more combinations, i.e., not only combine the // first DeclGroup with others, but we could combine // the second one and the third one. DV->push_back(DGR.getAsOpaquePtr()); return true; } void CombineGlobalVarDecl::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) { return; } if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doCombination(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void CombineGlobalVarDecl::doCombination(void) { TransAssert(TheDeclGroupRefs.size() == 2); void *P2 = TheDeclGroupRefs.pop_back_val(); void *P1 = TheDeclGroupRefs.pop_back_val(); DeclGroupRef FirstDGR = DeclGroupRef::getFromOpaquePtr(P1); DeclGroupRef SecondDGR = DeclGroupRef::getFromOpaquePtr(P2); SourceLocation EndLoc = RewriteHelper->getDeclGroupRefEndLoc(FirstDGR); std::string DStr; RewriteHelper->getDeclGroupStrAndRemove(SecondDGR, DStr); TheRewriter.InsertText(EndLoc, ", " + DStr, /*InsertAfter=*/false); } CombineGlobalVarDecl::~CombineGlobalVarDecl(void) { for(TypeToDeclMap::iterator I = AllDeclGroups.begin(), E = AllDeclGroups.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/CombineGlobalVarDecl.h000066400000000000000000000026371402162750500212030ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COMBINE_GLOBAL_VAR_DECL_H #define COMBINE_GLOBAL_VAR_DECL_H #include #include #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class Type; } class CombineGlobalVarDecl : public Transformation { public: CombineGlobalVarDecl(const char *TransName, const char *Desc) : Transformation(TransName, Desc) { } ~CombineGlobalVarDecl(void); private: typedef llvm::SmallVector DeclGroupVector; typedef llvm::DenseMap TypeToDeclMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doCombination(); TypeToDeclMap AllDeclGroups; llvm::SmallVector TheDeclGroupRefs; // Unimplemented CombineGlobalVarDecl(void); CombineGlobalVarDecl(const CombineGlobalVarDecl &); void operator=(const CombineGlobalVarDecl &); }; #endif cvise-2.3.0/clang_delta/CombineLocalVarDecl.cpp000066400000000000000000000105461402162750500213660ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "CombineLocalVarDecl.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Combine local variable declarations with the same type. \ This transformation records the location of the first \ local variable declaration, and tries to combine other \ declarations in the same DeclContext as the first one. \ For example, for the following cod3: \n\ int foo(void) { \n\ int x; \n\ int y; \n\ if (...) { \n\ int z; \n\ } \n\ } \n\ We will only combine x and y, and won't touch z, \ because z is not in the same DeclContext as x and y. \ Note that this transformation is unsound for the same \ reason as combine-global-var. \n"; static RegisterTransformation Trans("combine-local-var", DescriptionMsg); class CombLocalVarCollectionVisitor : public RecursiveASTVisitor { public: explicit CombLocalVarCollectionVisitor(CombineLocalVarDecl *Instance) : ConsumerInstance(Instance) { } bool VisitCompoundStmt(CompoundStmt *DS); private: const Type *getTypeFromDeclStmt(DeclStmt *DS); CombineLocalVarDecl *ConsumerInstance; }; const Type *CombLocalVarCollectionVisitor::getTypeFromDeclStmt(DeclStmt *DS) { Decl *D; if (DS->isSingleDecl()) { D = DS->getSingleDecl(); } else { DeclGroupRef DGR = DS->getDeclGroup(); DeclGroupRef::iterator I = DGR.begin(); D = (*I); } VarDecl *VD = dyn_cast(D); if (!VD) return NULL; return VD->getType().getTypePtr(); } bool CombLocalVarCollectionVisitor::VisitCompoundStmt(CompoundStmt *CS) { if (ConsumerInstance->isInIncludedFile(CS)) return true; ConsumerInstance->DeclStmts.clear(); for (CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); I != E; ++I) { DeclStmt *DS = dyn_cast(*I); if (!DS) continue; const Type *T = getTypeFromDeclStmt(DS); if (!T) continue; const Type *CanonicalT = ConsumerInstance->Context->getCanonicalType(T); llvm::DenseMap::iterator TI = ConsumerInstance->DeclStmts.find(CanonicalT); if (TI == ConsumerInstance->DeclStmts.end()) { ConsumerInstance->DeclStmts[CanonicalT] = DS; } else { ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum != ConsumerInstance->TransformationCounter) continue; ConsumerInstance->TheDeclStmts.push_back((*TI).second); ConsumerInstance->TheDeclStmts.push_back(DS); } } return true; } void CombineLocalVarDecl::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new CombLocalVarCollectionVisitor(this); } bool CombineLocalVarDecl::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void CombineLocalVarDecl::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) { return; } if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doCombination(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void CombineLocalVarDecl::doCombination(void) { TransAssert(TheDeclStmts.size() == 2); DeclStmt *DS2 = TheDeclStmts.pop_back_val(); DeclStmt *DS1 = TheDeclStmts.pop_back_val(); SourceLocation EndLoc = RewriteHelper->getDeclStmtEndLoc(DS1); std::string DStr; RewriteHelper->getDeclStmtStrAndRemove(DS2, DStr); TheRewriter.InsertText(EndLoc, ", " + DStr, /*InsertAfter=*/false); } CombineLocalVarDecl::~CombineLocalVarDecl(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/CombineLocalVarDecl.h000066400000000000000000000027631402162750500210350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COMBINE_LOCAL_VAR_DECL_H #define COMBINE_LOCAL_VAR_DECL_H #include #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class DeclStmt; class CompoundStmt; class Type; } class CombLocalVarCollectionVisitor; class CombineLocalVarDecl : public Transformation { friend class CombLocalVarCollectionVisitor; public: CombineLocalVarDecl(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL) { } ~CombineLocalVarDecl(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doCombination(); llvm::DenseMap DeclStmts; llvm::SmallVector TheDeclStmts; CombLocalVarCollectionVisitor *CollectionVisitor; // Unimplemented CombineLocalVarDecl(void); CombineLocalVarDecl(const CombineLocalVarDecl &); void operator=(const CombineLocalVarDecl &); }; #endif cvise-2.3.0/clang_delta/CommonParameterRewriteVisitor.h000066400000000000000000000124161402162750500232540ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COMMON_PARAMETER_REWRITE_VISITOR_H #define COMMON_PARAMETER_REWRITE_VISITOR_H #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "clang/AST/RecursiveASTVisitor.h" template class CommonParameterRewriteVisitor : public clang::RecursiveASTVisitor { public: explicit CommonParameterRewriteVisitor(Trans *Instance) : ConsumerInstance(Instance) { } bool VisitCallExpr(clang::CallExpr *CallE); bool VisitFunctionDecl(clang::FunctionDecl *FD); bool VisitCXXConstructExpr(clang::CXXConstructExpr *CE); void rewriteAllExprs(void); protected: clang::SmallVector AllCallExprs; clang::SmallVector AllConstructExprs; typedef llvm::SmallPtrSet DeclContextSet; bool rewriteOneCallExpr(clang::CallExpr *E); bool rewriteOneConstructExpr(const clang::CXXConstructExpr *CE); Trans *ConsumerInstance; }; template bool CommonParameterRewriteVisitor::VisitCXXConstructExpr( clang::CXXConstructExpr *CE) { const clang::CXXConstructorDecl *CtorD = CE->getConstructor(); if (CtorD->getCanonicalDecl() == ConsumerInstance->TheFuncDecl) AllConstructExprs.push_back(CE); return true; } template bool CommonParameterRewriteVisitor::VisitFunctionDecl( clang::FunctionDecl *FD) { clang::FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (CanonicalFD == ConsumerInstance->TheFuncDecl) return ConsumerInstance->rewriteFuncDecl(FD); return true; } template bool CommonParameterRewriteVisitor::rewriteOneCallExpr( clang::CallExpr *E) { return ConsumerInstance->RewriteHelper-> removeArgFromCallExpr(E, ConsumerInstance->TheParamPos); } template bool CommonParameterRewriteVisitor::rewriteOneConstructExpr( const clang::CXXConstructExpr *CE) { return ConsumerInstance->RewriteHelper-> removeArgFromCXXConstructExpr(CE, ConsumerInstance->TheParamPos); } template void CommonParameterRewriteVisitor::rewriteAllExprs(void) { while (!AllCallExprs.empty()) { clang::CallExpr *CallE = AllCallExprs.pop_back_val(); rewriteOneCallExpr(CallE); } while (!AllConstructExprs.empty()) { const clang::CXXConstructExpr *CE = AllConstructExprs.pop_back_val(); rewriteOneConstructExpr(CE); } } template bool CommonParameterRewriteVisitor::VisitCallExpr( clang::CallExpr *CallE) { const clang::FunctionDecl *CalleeDecl = NULL; const clang::Expr *E = CallE->getCallee(); if (const clang::UnresolvedLookupExpr *UE = llvm::dyn_cast(E)) { clang::DeclarationName DName = UE->getName(); TransAssert(((DName.getNameKind() == clang::DeclarationName::Identifier) || (DName.getNameKind() == clang::DeclarationName::CXXOperatorName)) && "Not an indentifier!"); if (const clang::NestedNameSpecifier *NNS = UE->getQualifier()) { if (const clang::DeclContext *Ctx = ConsumerInstance->getDeclContextFromSpecifier(NNS)) { DeclContextSet VisitedCtxs; CalleeDecl = ConsumerInstance->lookupFunctionDecl(DName, Ctx, VisitedCtxs); } } if (!CalleeDecl) { DeclContextSet VisitedCtxs; CalleeDecl = ConsumerInstance->lookupFunctionDecl(DName, ConsumerInstance->TheFuncDecl->getLookupParent(), VisitedCtxs); } if (!CalleeDecl) return true; } else { CalleeDecl = CallE->getDirectCallee(); if (!CalleeDecl) { return true; } } if (clang::FunctionTemplateDecl *TheTmplFuncD = ConsumerInstance->TheFuncDecl->getDescribedFunctionTemplate()) { clang::FunctionTemplateDecl *TmplFuncD; if (CalleeDecl->isTemplateInstantiation()) TmplFuncD = CalleeDecl->getPrimaryTemplate(); else TmplFuncD = CalleeDecl->getDescribedFunctionTemplate(); if (!TmplFuncD || (TmplFuncD->getCanonicalDecl() != TheTmplFuncD->getCanonicalDecl())) return true; } if (clang::FunctionDecl *InstFuncDecl = CalleeDecl->getInstantiatedFromMemberFunction()) { CalleeDecl = InstFuncDecl; } if (CalleeDecl->getCanonicalDecl() != ConsumerInstance->TheFuncDecl) { return true; } // We now have a correct CallExpr // Here we only collect these valid CallExprs, and // will rewrite them later in a reverse order. // The reason is that if we have code like below: // foo(foo(1)); // we want to rewrite the nested foo(1) first. // If we rewrite the outside foo first, we will // end up with bad transformation when we try to // rewrite foo(1), which has been removed. AllCallExprs.push_back(CallE); return true; } #endif cvise-2.3.0/clang_delta/CommonRenameClassRewriteVisitor.h000066400000000000000000000335721402162750500235370ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COMMON_RENAME_CLASS_REWRITE_VISITOR_H #define COMMON_RENAME_CLASS_REWRITE_VISITOR_H #include "llvm/ADT/SmallPtrSet.h" #include "clang/AST/RecursiveASTVisitor.h" class Transformation; namespace clang_delta_common_visitor { using namespace clang; template class CommonRenameClassRewriteVisitor : public RecursiveASTVisitor { public: CommonRenameClassRewriteVisitor(Transformation *Instance, Rewriter *RT, RewriteUtils *Helper, const CXXRecordDecl *CXXRD, const std::string &Name) : ConsumerInstance(Instance), TheRewriter(RT), RewriteHelper(Helper), TheCXXRecordDecl(CXXRD), NewNameStr(Name) { } T &getDerived() { return *static_cast(this); }; bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); bool VisitCXXConstructorDecl(CXXConstructorDecl *CtorDecl); bool VisitCXXDestructorDecl(CXXDestructorDecl *DtorDecl); bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE); bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TyLoc); bool VisitRecordTypeLoc(RecordTypeLoc RTLoc); bool VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TSPLoc); bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc); bool VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc DTSLoc); bool VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); bool VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *TSD); bool TraverseConstructorInitializer(CXXCtorInitializer *Init); bool VisitUsingDecl(UsingDecl *D); private: typedef llvm::SmallPtrSet LocPtrSet; void renameTemplateName(TemplateName TmplName, SourceLocation LocStart); bool getNewName(const CXXRecordDecl *CXXRD, std::string &NewName); bool getNewNameByName(const std::string &Name, std::string &NewName); LocPtrSet VisitedLocs; Transformation *ConsumerInstance; Rewriter *TheRewriter; RewriteUtils *RewriteHelper; const CXXRecordDecl *TheCXXRecordDecl; std::string NewNameStr; }; template bool CommonRenameClassRewriteVisitor::VisitUsingDecl(UsingDecl *D) { DeclarationNameInfo NameInfo = D->getNameInfo(); DeclarationName DeclName = NameInfo.getName(); if (DeclName.getNameKind() != DeclarationName::Identifier) return true; IdentifierInfo *IdInfo = DeclName.getAsIdentifierInfo(); std::string IdName = IdInfo->getName().str(); std::string Name; if (getNewNameByName(IdName, Name)) { SourceLocation LocStart = NameInfo.getBeginLoc(); TheRewriter->ReplaceText(LocStart, IdName.size(), Name); } return true; } template bool CommonRenameClassRewriteVisitor::TraverseConstructorInitializer( CXXCtorInitializer *Init) { if (Init->isBaseInitializer() && !Init->isWritten()) return true; if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) getDerived().TraverseTypeLoc(TInfo->getTypeLoc()); if (Init->isWritten()) getDerived().TraverseStmt(Init->getInit()); return true; } template bool CommonRenameClassRewriteVisitor:: VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { const Type *Ty = D->getInjectedSpecializationType().getTypePtr(); TransAssert(Ty && "Bad TypePtr!"); const TemplateSpecializationType *TST = dyn_cast(Ty); TransAssert(TST && "Bad TemplateSpecializationType!"); TemplateName TplName = TST->getTemplateName(); const TemplateDecl *TplD = TplName.getAsTemplateDecl(); TransAssert(TplD && "Invalid TemplateDecl!"); NamedDecl *ND = TplD->getTemplatedDecl(); TransAssert(ND && "Invalid NamedDecl!"); const CXXRecordDecl *CXXRD = dyn_cast(ND); TransAssert(CXXRD && "Invalid CXXRecordDecl!"); std::string Name; if (getNewName(CXXRD, Name)) { const TypeSourceInfo *TyInfo = D->getTypeAsWritten(); if (!TyInfo) return true; TypeLoc TyLoc = TyInfo->getTypeLoc(); SourceLocation LocStart = TyLoc.getBeginLoc(); TransAssert(LocStart.isValid() && "Invalid Location!"); TheRewriter->ReplaceText(LocStart, CXXRD->getNameAsString().size(), Name); } return true; } // ISSUE: I am not sure why, but RecursiveASTVisitor doesn't recursively // visit base classes from explicit template specialization, e.g., // struct A { }; // template class B : public A { }; // template<> class B : public A { }; // In the above case, A won't be touched. // So we have to do it manually template bool CommonRenameClassRewriteVisitor::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *TSD) { if (!TSD->isExplicitSpecialization() || !TSD->isCompleteDefinition()) return true; for (CXXRecordDecl::base_class_const_iterator I = TSD->bases_begin(), E = TSD->bases_end(); I != E; ++I) { TypeSourceInfo *TSI = (*I).getTypeSourceInfo(); TransAssert(TSI && "Bad TypeSourceInfo!"); getDerived().TraverseTypeLoc(TSI->getTypeLoc()); } return true; } template bool CommonRenameClassRewriteVisitor::VisitCXXRecordDecl( CXXRecordDecl *CXXRD) { std::string Name; if (!getNewName(CXXRD, Name)) return true; void *LocPtr = CXXRD->getLocation().getPtrEncoding(); if (VisitedLocs.count(LocPtr)) return true; VisitedLocs.insert(LocPtr); if (ConsumerInstance->isDeclaringRecordDecl(CXXRD) && CXXRD->isThisDeclarationADefinition()) { RewriteHelper->replaceRecordDeclDef(CXXRD, Name); } else { RewriteHelper->replaceRecordDeclName(CXXRD, Name); } return true; } template bool CommonRenameClassRewriteVisitor::VisitCXXConstructorDecl (CXXConstructorDecl *CtorDecl) { const DeclContext *Ctx = CtorDecl->getDeclContext(); const CXXRecordDecl *CXXRD = dyn_cast(Ctx); TransAssert(CXXRD && "Invalid CXXRecordDecl"); std::string Name; if (getNewName(CXXRD, Name)) RewriteHelper->replaceFunctionDeclName(CtorDecl, Name); return true; } template bool CommonRenameClassRewriteVisitor::VisitCXXDestructorDecl( CXXDestructorDecl *DtorDecl) { const DeclContext *Ctx = DtorDecl->getDeclContext(); const CXXRecordDecl *CXXRD = dyn_cast(Ctx); TransAssert(CXXRD && "Invalid CXXRecordDecl"); // Avoid duplicated VisitDtor. // For example, in the code below: // template // class SomeClass { // public: // ~SomeClass() {} // }; // ~SomeClass's TypeLoc is represented as TemplateSpecializationTypeLoc // In this case, ~SomeClass will be renamed from // VisitTemplateSpecializationTypeLoc. DeclarationNameInfo NameInfo = DtorDecl->getNameInfo(); if ( TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) { TypeLoc DtorLoc = TSInfo->getTypeLoc(); if (!DtorLoc.isNull() && (DtorLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)) return true; } SourceLocation StartLoc = DtorDecl->getLocation(); // skip '~' StartLoc = StartLoc.getLocWithOffset(1); StartLoc = RewriteHelper->getLocationAfterSkiping(StartLoc, ' '); void *LocPtr = StartLoc.getPtrEncoding(); if (VisitedLocs.count(LocPtr)) return true; VisitedLocs.insert(LocPtr); std::string Name; if (getNewName(CXXRD, Name)) { RewriteHelper->replaceCXXDestructorDeclName(DtorDecl, Name); } return true; } template bool CommonRenameClassRewriteVisitor::VisitInjectedClassNameTypeLoc( InjectedClassNameTypeLoc TyLoc) { const CXXRecordDecl *CXXRD = TyLoc.getDecl(); TransAssert(CXXRD && "Invalid CXXRecordDecl!"); std::string Name; if (getNewName(CXXRD, Name)) { SourceLocation LocStart = TyLoc.getBeginLoc(); TransAssert(LocStart.isValid() && "Invalid Location!"); void *LocPtr = LocStart.getPtrEncoding(); if (VisitedLocs.count(LocPtr)) return true; VisitedLocs.insert(LocPtr); TheRewriter->ReplaceText(LocStart, CXXRD->getNameAsString().size(), Name); } return true; } template bool CommonRenameClassRewriteVisitor::VisitCXXMemberCallExpr( CXXMemberCallExpr *CE) { const CXXRecordDecl *CXXRD = CE->getRecordDecl(); // getRecordDEcl could return NULL if getImplicitObjectArgument() // returns NULL if (!CXXRD) return true; std::string Name; if (getNewName(CXXRD, Name)) { RewriteHelper->replaceCXXDtorCallExpr(CE, Name); } return true; } template bool CommonRenameClassRewriteVisitor::VisitRecordTypeLoc(RecordTypeLoc RTLoc) { const Type *Ty = RTLoc.getTypePtr(); if (Ty->isUnionType()) return true; const CXXRecordDecl *RD = dyn_cast(RTLoc.getDecl()); if (!RD) return true; std::string Name; if (!getNewName(RD, Name)) return true; // Let VisitCXXRecordDecl handle this case. if (ConsumerInstance->isDeclaringRecordDecl(RD)) return true; // Avoid duplicated rewrites to Decls from the same DeclGroup, e.g., // struct S s1, s2 SourceLocation LocStart = RTLoc.getBeginLoc(); void *LocPtr = LocStart.getPtrEncoding(); if (VisitedLocs.count(LocPtr)) return true; VisitedLocs.insert(LocPtr); RewriteHelper->replaceRecordType(RTLoc, Name); return true; } template bool CommonRenameClassRewriteVisitor:: VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc DTSLoc) { const Type *Ty = DTSLoc.getTypePtr(); const DependentTemplateSpecializationType *DTST = dyn_cast(Ty); TransAssert(DTST && "Bad DependentTemplateSpecializationType!"); const IdentifierInfo *IdInfo = DTST->getIdentifier(); std::string IdName = IdInfo->getName().str(); std::string Name; if (getNewNameByName(IdName, Name)) { SourceLocation LocStart = DTSLoc.getTemplateNameLoc(); TheRewriter->ReplaceText(LocStart, IdName.size(), Name); } return true; } template void CommonRenameClassRewriteVisitor::renameTemplateName( TemplateName TmplName, SourceLocation LocStart) { if (TmplName.getKind() == TemplateName::DependentTemplate) return; const TemplateDecl *TmplD = TmplName.getAsTemplateDecl(); TransAssert(TmplD && "Invalid TemplateDecl!"); NamedDecl *ND = TmplD->getTemplatedDecl(); // in some cases, ND could be NULL, e.g., the // template template parameter code below: // template class BBB> // struct AAA { // template // struct CCC { // static BBB a; // }; // }; // where we don't know BBB if (!ND) return; const CXXRecordDecl *CXXRD = dyn_cast(ND); if (!CXXRD) return; std::string Name; if (getNewName(CXXRD, Name)) { TheRewriter->ReplaceText(LocStart, CXXRD->getNameAsString().size(), Name); } } // ISSUE: we don't have loc info for TemplateName, so we have to // overload RecursiveASTVisitor TraverseTemplateArgumentLoc // function, or else we will omit arguments for template template // parameters template bool CommonRenameClassRewriteVisitor::TraverseTemplateArgumentLoc( const TemplateArgumentLoc &ArgLoc) { const TemplateArgument &Arg = ArgLoc.getArgument(); switch (Arg.getKind()) { case TemplateArgument::NullPtr: case TemplateArgument::Null: case TemplateArgument::Declaration: case TemplateArgument::Integral: return true; case TemplateArgument::Type: { if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo()) return getDerived().TraverseTypeLoc(TSI->getTypeLoc()); else return getDerived().TraverseType(Arg.getAsType()); } case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { if (ArgLoc.getTemplateQualifierLoc()) { getDerived().TraverseNestedNameSpecifierLoc( ArgLoc.getTemplateQualifierLoc()); } TemplateName TmplName = Arg.getAsTemplateOrTemplatePattern(); getDerived().TraverseTemplateName(Arg.getAsTemplateOrTemplatePattern()); renameTemplateName(TmplName, ArgLoc.getLocation()); return true; } case TemplateArgument::Expression: return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); case TemplateArgument::Pack: return getDerived().TraverseTemplateArguments(Arg.pack_begin(), Arg.pack_size()); } return true; } template bool CommonRenameClassRewriteVisitor::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TSPLoc) { const Type *Ty = TSPLoc.getTypePtr(); const TemplateSpecializationType *TST = dyn_cast(Ty); TransAssert(TST && "Bad TemplateSpecializationType!"); TemplateName TmplName = TST->getTemplateName(); renameTemplateName(TmplName, TSPLoc.getTemplateNameLoc()); return true; } template bool CommonRenameClassRewriteVisitor::getNewName(const CXXRecordDecl *CXXRD, std::string &NewName) { const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (CanonicalRD == TheCXXRecordDecl) { NewName = NewNameStr; return true; } else { NewName = ""; return false; } } template bool CommonRenameClassRewriteVisitor::getNewNameByName( const std::string &Name, std::string &NewName) { if (TheCXXRecordDecl && (Name == TheCXXRecordDecl->getNameAsString())) { NewName = NewNameStr; return true; } else { NewName = ""; return false; } } } // end namespace clang_delta_common_visitor #endif cvise-2.3.0/clang_delta/CommonStatementVisitor.h000066400000000000000000000106301402162750500217320ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COMMON_STATEMENT_VISITOR_H #define COMMON_STATEMENT_VISITOR_H #include "clang/AST/RecursiveASTVisitor.h" template class CommonStatementVisitor : public clang::RecursiveASTVisitor { public: CommonStatementVisitor() : CurrentFuncDecl(NULL), CurrentStmt(NULL), NeedParen(false) { } T &getDerived() { return *static_cast(this); }; void setCurrentFunctionDecl(clang::FunctionDecl *FD) { CurrentFuncDecl = FD; } bool VisitCompoundStmt(clang::CompoundStmt *S); bool VisitIfStmt(clang::IfStmt *IS); bool VisitForStmt(clang::ForStmt *FS); bool VisitWhileStmt(clang::WhileStmt *WS); bool VisitDoStmt(clang::DoStmt *DS); bool VisitCaseStmt(clang::CaseStmt *CS); bool VisitDefaultStmt(clang::DefaultStmt *DS); bool VisitCXXTryStmt(clang::CXXTryStmt *DS); void visitNonCompoundStmt(clang::Stmt *S); protected: clang::FunctionDecl *CurrentFuncDecl; clang::Stmt *CurrentStmt; bool NeedParen; }; template bool CommonStatementVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) { for (clang::CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); I != E; ++I) { CurrentStmt = (*I); getDerived().TraverseStmt(*I); } return false; } template void CommonStatementVisitor::visitNonCompoundStmt(clang::Stmt *S) { if (!S) return; clang::CompoundStmt *CS = llvm::dyn_cast(S); if (CS) { VisitCompoundStmt(CS); return; } CurrentStmt = (S); NeedParen = true; getDerived().TraverseStmt(S); NeedParen = false; } // It is used to handle the case where if-then or else branch // is not treated as a CompoundStmt. So it cannot be traversed // from VisitCompoundStmt, e.g., // if (x) // foo(bar()) template bool CommonStatementVisitor::VisitIfStmt(clang::IfStmt *IS) { clang::Expr *E = IS->getCond(); getDerived().TraverseStmt(E); clang::Stmt *ThenB = IS->getThen(); visitNonCompoundStmt(ThenB); clang::Stmt *ElseB = IS->getElse(); visitNonCompoundStmt(ElseB); return false; } // It causes unsound transformation because // the semantics of loop execution has been changed. // For example, // int foo(int x) // { // int i; // for(i = 0; i < bar(bar(x)); i++) // ... // } // will be transformed to: // int foo(int x) // { // int i; // int tmp_var = bar(x); // for(i = 0; i < bar(tmp_var); i++) // ... // } template bool CommonStatementVisitor::VisitForStmt(clang::ForStmt *FS) { clang::Stmt *Init = FS->getInit(); getDerived().TraverseStmt(Init); clang::Expr *Cond = FS->getCond(); getDerived().TraverseStmt(Cond); clang::Expr *Inc = FS->getInc(); getDerived().TraverseStmt(Inc); clang::Stmt *Body = FS->getBody(); visitNonCompoundStmt(Body); return false; } template bool CommonStatementVisitor::VisitWhileStmt(clang::WhileStmt *WS) { clang::Expr *E = WS->getCond(); getDerived().TraverseStmt(E); clang::Stmt *Body = WS->getBody(); visitNonCompoundStmt(Body); return false; } template bool CommonStatementVisitor::VisitDoStmt(clang::DoStmt *DS) { clang::Expr *E = DS->getCond(); getDerived().TraverseStmt(E); clang::Stmt *Body = DS->getBody(); visitNonCompoundStmt(Body); return false; } template bool CommonStatementVisitor::VisitCaseStmt(clang::CaseStmt *CS) { clang::Stmt *Body = CS->getSubStmt(); visitNonCompoundStmt(Body); return false; } template bool CommonStatementVisitor::VisitDefaultStmt(clang::DefaultStmt *DS) { clang::Stmt *Body = DS->getSubStmt(); visitNonCompoundStmt(Body); return false; } template bool CommonStatementVisitor::VisitCXXTryStmt(clang::CXXTryStmt *CS) { clang::CompoundStmt *TryBlock = CS->getTryBlock(); visitNonCompoundStmt(TryBlock); for (unsigned I = 0; I < CS->getNumHandlers(); ++I) { clang::CXXCatchStmt *CatchStmt = CS->getHandler(I); clang::Stmt *CatchBlock = CatchStmt->getHandlerBlock(); visitNonCompoundStmt(CatchBlock); } return false; } #endif cvise-2.3.0/clang_delta/CommonTemplateArgumentVisitor.h000066400000000000000000000070171402162750500232510ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COMMON_TEMPLATE_ARGUMENT_VISITOR_H #define COMMON_TEMPLATE_ARGUMENT_VISITOR_H #include "clang/AST/RecursiveASTVisitor.h" namespace clang_delta_common_visitor { template class CommonTemplateArgumentVisitor : public clang::RecursiveASTVisitor { public: explicit CommonTemplateArgumentVisitor(Trans *Instance) : ConsumerInstance(Instance) { } bool VisitClassTemplatePartialSpecializationDecl( clang::ClassTemplatePartialSpecializationDecl *D); bool VisitTemplateSpecializationTypeLoc( clang::TemplateSpecializationTypeLoc TLoc); bool VisitFunctionDecl(clang::FunctionDecl *D); bool VisitDeclRefExpr(clang::DeclRefExpr *E); protected: Trans *ConsumerInstance; }; template bool CommonTemplateArgumentVisitor:: VisitTemplateSpecializationTypeLoc( clang::TemplateSpecializationTypeLoc TLoc) { ConsumerInstance->handleTemplateSpecializationTypeLoc(TLoc); return true; } template bool CommonTemplateArgumentVisitor:: VisitClassTemplatePartialSpecializationDecl( clang::ClassTemplatePartialSpecializationDecl *D) { ConsumerInstance->handleTemplateArgumentLocs( D->getSpecializedTemplate(), D->getTemplateArgsAsWritten()->getTemplateArgs(), D->getTemplateArgsAsWritten()->NumTemplateArgs); return true; } template bool CommonTemplateArgumentVisitor::VisitFunctionDecl( clang::FunctionDecl *D) { const clang::FunctionTemplateSpecializationInfo *FTSI = D->getTemplateSpecializationInfo(); if (!FTSI) return true; if ((FTSI->getTemplateSpecializationKind() == clang::TSK_Undeclared) || (FTSI->getTemplateSpecializationKind() == clang::TSK_ImplicitInstantiation)) return true; if (const clang::ASTTemplateArgumentListInfo *TALI = FTSI->TemplateArgumentsAsWritten) { ConsumerInstance->handleTemplateArgumentLocs( D->getPrimaryTemplate(), TALI->getTemplateArgs(), TALI->NumTemplateArgs); } return true; } template bool CommonTemplateArgumentVisitor::VisitDeclRefExpr( clang::DeclRefExpr *E) { const clang::ValueDecl *VD = E->getDecl(); const clang::TemplateDecl *TempD = NULL; if (const clang::FunctionDecl *FD = clang::dyn_cast(VD)) { TempD = FD->getDescribedFunctionTemplate(); } else { const clang::Type *Ty = VD->getType().getTypePtr(); if (const clang::ArrayType *AT = clang::dyn_cast(Ty)) { Ty = AT->getElementType().getTypePtr(); } if (Ty->isPointerType() || Ty->isReferenceType()) Ty = ConsumerInstance->getBasePointerElemType(Ty); const clang::CXXRecordDecl *CXXRD = ConsumerInstance->getBaseDeclFromType(Ty); if (!CXXRD) return true; TempD = CXXRD->getDescribedClassTemplate(); } if (!TempD) return true; ConsumerInstance->handleTemplateArgumentLocs(TempD, E->getTemplateArgs(), E->getNumTemplateArgs()); return true; } #endif } // end namespace clang_delta_common_visitor cvise-2.3.0/clang_delta/CopyPropagation.cpp000066400000000000000000000276351402162750500207230ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "CopyPropagation.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "A simply copy propagation pass. \ Copy propagation only happens to: \n\ * variables \n\ * member expressions \n\ * array subscript expressions \n\ Only those value obtained through simple \ assignment or initilizer will be propagated. \ Here \"simple assignment\" is defined as: \n\ x = y \n\ where both x and y are either variables, member expressions \ or array subscript expressions (y could be a constant). \ For example, x = foo() is not considered as a simple assignment. \ Copy propagation of LHS will stop upon any non-simple assignment. \ Therefore, in the above example, foo() will not be propagated. \n"; static RegisterTransformation Trans("copy-propagation", DescriptionMsg); namespace { class ArraySubscriptVisitor : public RecursiveASTVisitor { public: explicit ArraySubscriptVisitor(const VarDecl *VD) : ReferencedVD(VD), HasReference(false) { } bool VisitVarDecl(VarDecl *VD); bool hasReferencedVD() { return HasReference; } private: const VarDecl *ReferencedVD; bool HasReference; }; bool ArraySubscriptVisitor::VisitVarDecl(VarDecl *VD) { if (VD->getCanonicalDecl() == ReferencedVD) HasReference = true; return true; } } // End anonymous namespace class CopyPropCollectionVisitor : public RecursiveASTVisitor { public: explicit CopyPropCollectionVisitor(CopyPropagation *Instance) : ConsumerInstance(Instance), BeingWritten(false), BeingAddrTaken(false), BeingIncDec(false), BeingPartial(false) { } bool VisitVarDecl(VarDecl *VD); bool VisitBinaryOperator(BinaryOperator *BO); bool VisitUnaryOperator(UnaryOperator *UO); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitMemberExpr(MemberExpr *ME); bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); private: void resetFlags(void); CopyPropagation *ConsumerInstance; // Indicate if a var/memexpr/arraysubexpr is being written. // Set by updateExpr and reset by VisitDeclRefExpr bool BeingWritten; bool BeingAddrTaken; // It will be true for ++i, --i // In this case, we cannot copy-propagate a constant to i bool BeingIncDec; // For MemberExpr and ArraySubscriptExpr, we don't want to // track the partial element. For example, a[0][0][0], // VisitArraySubscriptExpr will visit: // a[0][0][0] // a[0][0] // a[0] // We only want to track the first one. This flag will be // reset when we reach a. bool BeingPartial; }; void CopyPropCollectionVisitor::resetFlags(void) { BeingWritten = false; BeingAddrTaken = false; BeingIncDec = false; BeingPartial = false; } bool CopyPropCollectionVisitor::VisitVarDecl(VarDecl *VD) { if (!VD->hasInit()) return true; const Expr *Init = VD->getInit(); if (ConsumerInstance->isValidExpr(Init)) { const VarDecl *CanonicalVD = VD->getCanonicalDecl(); ConsumerInstance->VarToExpr[CanonicalVD] = Init; } return true; } bool CopyPropCollectionVisitor::VisitBinaryOperator(BinaryOperator *BO) { if (!BO->isAssignmentOp() && !BO->isCompoundAssignmentOp()) return true; const Expr *Lhs = BO->getLHS()->IgnoreParenCasts(); if (!ConsumerInstance->isValidLhs(Lhs)) return true; const Expr *Rhs = BO->getRHS()->IgnoreParenCasts(); BeingWritten = true; if (!ConsumerInstance->isValidExpr(Rhs)) { ConsumerInstance->invalidateExpr(Lhs); return true; } ConsumerInstance->updateExpr(Lhs, Rhs); return true; } bool CopyPropCollectionVisitor::VisitUnaryOperator(UnaryOperator *UO) { UnaryOperator::Opcode Op = UO->getOpcode(); if (Op == UO_AddrOf) { BeingAddrTaken = true; return true; } if (UO->isIncrementDecrementOp()) BeingIncDec = true; return true; } bool CopyPropCollectionVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { if (BeingWritten || BeingAddrTaken || BeingPartial) { resetFlags(); return true; } const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); // DRE could refer to FunctionDecl, etc if (!VD) return true; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); const Expr *CopyE = ConsumerInstance->VarToExpr[CanonicalVD]; if (!CopyE || (BeingIncDec && ConsumerInstance->isConstantExpr(CopyE))) { BeingIncDec = false; return true; } ConsumerInstance->addOneDominatedExpr(CopyE, DRE); return true; } bool CopyPropCollectionVisitor::VisitMemberExpr(MemberExpr *ME) { if (BeingWritten || BeingAddrTaken || BeingPartial) { return true; } if (!BeingPartial) BeingPartial = true; const Expr *CopyE = ConsumerInstance->MemberExprToExpr[ME]; if (!CopyE) { if (!ConsumerInstance->VisitedMEAndASE.count(ME)) { CopyE = ConsumerInstance->getMemberExprElem(ME); } else { return true; } } if (!CopyE || (BeingIncDec && ConsumerInstance->isConstantExpr(CopyE))) { BeingIncDec = false; BeingPartial = false; return true; } ConsumerInstance->addOneDominatedExpr(CopyE, ME); return true; } bool CopyPropCollectionVisitor::VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) { if (BeingWritten || BeingAddrTaken || BeingPartial) { return true; } if (!BeingPartial) BeingPartial = true; const Expr *CopyE = ConsumerInstance->ArraySubToExpr[ASE]; if (!CopyE) { if (!ConsumerInstance->VisitedMEAndASE.count(ASE)) { CopyE = ConsumerInstance->getArraySubscriptElem(ASE); } else { return true; } } if (!CopyE || (BeingIncDec && ConsumerInstance->isConstantExpr(CopyE))) { BeingPartial = false; BeingIncDec = false; return true; } ConsumerInstance->addOneDominatedExpr(CopyE, ASE); return true; } void CopyPropagation::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new CopyPropCollectionVisitor(this); } bool CopyPropagation::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) CollectionVisitor->TraverseDecl(*I); return true; } void CopyPropagation::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheCopyExpr && "NULL TheCopyExpr!"); doCopyPropagation(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } // Note we skip InitListExpr, so some likely valid cases won't be handled: // int i = {1}; // But this kind of code almost couldn't happen, // because c_delta will remove {} pair. bool CopyPropagation::isValidExpr(const Expr *Exp) { const Expr *E = Exp->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::FloatingLiteralClass: case Expr::StringLiteralClass: case Expr::IntegerLiteralClass: case Expr::GNUNullExprClass: case Expr::CharacterLiteralClass: case Expr::DeclRefExprClass: case Expr::MemberExprClass: case Expr::ArraySubscriptExprClass: // Fall-through return true; default: return false; } TransAssert(0 && "Unreachable code!"); return false; } bool CopyPropagation::isValidLhs(const Expr *Lhs) { const Expr *E = Lhs->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::DeclRefExprClass: case Expr::MemberExprClass: case Expr::ArraySubscriptExprClass: // Fall-through return true; default: return false; } TransAssert(0 && "Unreachable code!"); return false; } bool CopyPropagation::isConstantExpr(const Expr *Exp) { const Expr *E = Exp->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::FloatingLiteralClass: case Expr::StringLiteralClass: case Expr::IntegerLiteralClass: case Expr::GNUNullExprClass: case Expr::CharacterLiteralClass: // Fall-through return true; default: return false; } TransAssert(0 && "Unreachable code!"); return false; } void CopyPropagation::updateExpr(const Expr *E, const Expr *CopyE) { switch (E->getStmtClass()) { case Expr::DeclRefExprClass: { const DeclRefExpr *DRE = dyn_cast(E); const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); TransAssert(VD && "Bad VD!"); const VarDecl *CanonicalVD = VD->getCanonicalDecl(); VarToExpr[CanonicalVD] = CopyE; return; } case Expr::MemberExprClass: { const MemberExpr *ME = dyn_cast(E); MemberExprToExpr[ME] = CopyE; VisitedMEAndASE.insert(E); return; } case Expr::ArraySubscriptExprClass: { const ArraySubscriptExpr *ASE = dyn_cast(E); ArraySubToExpr[ASE] = CopyE; VisitedMEAndASE.insert(E); return; } default: TransAssert(0 && "Uncatched Expr!"); } TransAssert(0 && "Unreachable code!"); } void CopyPropagation::invalidateExpr(const Expr *E) { updateExpr(E, NULL); } const VarDecl *CopyPropagation::getCanonicalRefVarDecl(const Expr *E) { const DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return NULL; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); // DRE could refer to FunctionDecl, etc if (!VD) return NULL; return VD->getCanonicalDecl(); } bool CopyPropagation::isRefToTheSameVar(const Expr *CopyE, const Expr *DominatedE) { const VarDecl *DominatedVD = getCanonicalRefVarDecl(DominatedE); if (!DominatedVD) return false; const VarDecl *CopyVD = getCanonicalRefVarDecl(CopyE); if (CopyVD) return CopyVD == DominatedVD; if (const ArraySubscriptExpr *ASE = dyn_cast(CopyE)) { ArraySubscriptVisitor V(DominatedVD); V.TraverseStmt(const_cast(ASE->getIdx())); return !V.hasReferencedVD(); } return false; } bool CopyPropagation::hasSameStringRep(const Expr *CopyE, const Expr *DominatedE) { std::string CopyStr, DominatedStr; RewriteHelper->getExprString(CopyE, CopyStr); RewriteHelper->getExprString(DominatedE, DominatedStr); return (CopyStr == DominatedStr); } void CopyPropagation::addOneDominatedExpr(const Expr *CopyE, const Expr *DominatedE) { if (isInIncludedFile(CopyE) || isInIncludedFile(DominatedE)) return; if ((CopyE == DominatedE) || isRefToTheSameVar(CopyE, DominatedE) || hasSameStringRep(CopyE, DominatedE)) return; ExprSet *ESet = DominatedMap[CopyE]; if (!ESet) { ESet = new ExprSet(); TransAssert(ESet && "Couldn't new ExprSet"); DominatedMap[CopyE] = ESet; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) TheCopyExpr = CopyE; } ESet->insert(DominatedE); } void CopyPropagation::doCopyPropagation(void) { std::string CopyStr(""); RewriteHelper->getExprString(TheCopyExpr, CopyStr); ExprSet *ESet = DominatedMap[TheCopyExpr]; TransAssert(ESet && "Empty Expr Set!"); for (ExprSet::iterator I = ESet->begin(), E = ESet->end(); I != E; ++I) { RewriteHelper->replaceExpr((*I), CopyStr); } } CopyPropagation::~CopyPropagation(void) { delete CollectionVisitor; for (ExprToExprsMap::iterator I = DominatedMap.begin(), E = DominatedMap.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/CopyPropagation.h000066400000000000000000000067331402162750500203640ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2014 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef COPY_PROPAGATION_H #define COPY_PROPAGATION_H #include #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class Expr; class VarDecl; class MemberExpr; class ArraySubscriptExpr; } class CopyPropCollectionVisitor; class CopyPropagation : public Transformation { friend class CopyPropCollectionVisitor; public: CopyPropagation(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheCopyExpr(NULL) { } ~CopyPropagation(void); private: typedef llvm::DenseMap VarToExprMap; typedef llvm::DenseMap MemberExprToExprMap; typedef llvm::DenseMap ArraySubToExprMap; typedef llvm::SmallPtrSet ExprSet; typedef llvm::DenseMap ExprToExprsMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isValidExpr(const clang::Expr *E); bool isValidLhs(const clang::Expr *Lhs); void updateExpr(const clang::Expr *E, const clang::Expr *CopyE); void invalidateExpr(const clang::Expr *E); void addOneDominatedExpr(const clang::Expr *CopyE, const clang::Expr *DominatedE); const clang::VarDecl *getCanonicalRefVarDecl(const clang::Expr *E); bool isRefToTheSameVar(const clang::Expr *CopyE, const clang::Expr *DominatedE); bool hasSameStringRep(const clang::Expr *CopyE, const clang::Expr *DominatedE); void doCopyPropagation(void); bool isConstantExpr(const clang::Expr *Exp); // A mapping from a var to its value at the current processing point VarToExprMap VarToExpr; // A mapping from a member expr to its value at the current processing point MemberExprToExprMap MemberExprToExpr; // A mapping from a arraysubscript expr to its value at // the current processing point ArraySubToExprMap ArraySubToExpr; // Only hold visited MemberExpr and ArraySubscriptExpr. // Used for distinguishing a valid Member/ArraySubscript expr // and a Member/ArraySubscript expr which will get a copy from its // corresponding initializer. The advantage is that we don't have to // set up initial value for all the fields of a var which has an aggregate // type. We only need to retrieve the initial value of a field on demand. // We don't need to do this for VarDecl because we can directly get its // initial value. ExprSet VisitedMEAndASE; // A mapping from an Expr to its dominating Exprs ExprToExprsMap DominatedMap; CopyPropCollectionVisitor *CollectionVisitor; const clang::Expr *TheCopyExpr; // Unimplemented CopyPropagation(void); CopyPropagation(const CopyPropagation &); void operator=(const CopyPropagation &); }; #endif cvise-2.3.0/clang_delta/EmptyStructToInt.cpp000066400000000000000000000420201402162750500210470ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "EmptyStructToInt.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "llvm/ADT/StringRef.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Replace an empty struct with type of int. A struct is defined to be empty if \ it: \ * does not have any field; \n\ * does not have any base class; \n\ * is not a base class of another class; \n\ * is not described by any template; \n\ * has only one unreferenced field; \n\ * doesn't have self pointer reference\n"; static RegisterTransformation Trans("empty-struct-to-int", DescriptionMsg); class EmptyStructToIntASTVisitor : public RecursiveASTVisitor { public: explicit EmptyStructToIntASTVisitor(EmptyStructToInt *Instance) : ConsumerInstance(Instance) { } bool VisitRecordDecl(RecordDecl *RD); bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: EmptyStructToInt *ConsumerInstance; }; class EmptyStructToIntRewriteVisitor : public RecursiveASTVisitor { public: explicit EmptyStructToIntRewriteVisitor(EmptyStructToInt *Instance) : ConsumerInstance(Instance) { } bool VisitRecordTypeLoc(RecordTypeLoc RTLoc); bool VisitElaboratedTypeLoc(ElaboratedTypeLoc Loc); bool VisitRecordDecl(RecordDecl *RD); bool VisitVarDecl(VarDecl *VD); private: EmptyStructToInt *ConsumerInstance; }; bool EmptyStructToIntASTVisitor::VisitRecordDecl(RecordDecl *RD) { if (ConsumerInstance->isInIncludedFile(RD) || !ConsumerInstance->isValidRecordDecl(RD)) return true; const RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); if (ConsumerInstance->VisitedRecordDecls.count(CanonicalRD)) return true; ConsumerInstance->VisitedRecordDecls.insert(CanonicalRD); return true; } bool EmptyStructToIntASTVisitor::VisitCXXRecordDecl(CXXRecordDecl *CXXRD) { const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (ConsumerInstance->VisitedRecordDecls.count(CanonicalRD)) return true; if (!CanonicalRD->hasDefinition()) return true; for (CXXRecordDecl::base_class_const_iterator I = CanonicalRD->bases_begin(), E = CanonicalRD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = ConsumerInstance->getBaseDeclFromType(Ty); if (Base) ConsumerInstance->BaseClassDecls.insert(Base->getCanonicalDecl()); } return true; } bool EmptyStructToIntRewriteVisitor::VisitRecordTypeLoc(RecordTypeLoc RTLoc) { const RecordDecl *RD = RTLoc.getDecl(); if (RD->getCanonicalDecl() == ConsumerInstance->TheRecordDecl) { SourceLocation LocStart = RTLoc.getBeginLoc(); void *LocPtr = LocStart.getPtrEncoding(); if (ConsumerInstance->VisitedLocs.count(LocPtr)) return true; ConsumerInstance->VisitedLocs.insert(LocPtr); SourceLocation LocEnd = RTLoc.getEndLoc(); if (ConsumerInstance->isSourceRangeWithinRecordDecl( SourceRange(LocStart, LocEnd), RD)) { return true; } // handle a special case - // struct S1 { // struct { } S; // }; const IdentifierInfo *TypeId = RTLoc.getType().getBaseTypeIdentifier(); if (!TypeId) return true; ConsumerInstance->RewriteHelper->replaceRecordType(RTLoc, "int"); ConsumerInstance->Rewritten = true; } return true; } bool EmptyStructToIntRewriteVisitor::VisitElaboratedTypeLoc( ElaboratedTypeLoc Loc) { const ElaboratedType *ETy = dyn_cast(Loc.getTypePtr()); const Type *NamedTy = ETy->getNamedType().getTypePtr(); const RecordType *RDTy = NamedTy->getAs(); if (!RDTy) return true; const RecordDecl *RD = RDTy->getDecl(); TransAssert(RD && "NULL RecordDecl!"); if (RD->getCanonicalDecl() != ConsumerInstance->TheRecordDecl) { return true; } SourceLocation StartLoc = Loc.getBeginLoc(); if (StartLoc.isInvalid()) return true; TypeLoc TyLoc = Loc.getNamedTypeLoc(); SourceLocation EndLoc = TyLoc.getBeginLoc(); if (EndLoc.isInvalid()) return true; EndLoc = EndLoc.getLocWithOffset(-1); // This ElaboratedTypeLoc has been removed along with the RD if (ConsumerInstance->isSourceRangeWithinRecordDecl( SourceRange(StartLoc, EndLoc), RD)) { return true; } const char *StartBuf = ConsumerInstance->SrcManager->getCharacterData(StartLoc); const char *EndBuf = ConsumerInstance->SrcManager->getCharacterData(EndLoc); ConsumerInstance->Rewritten = true; // It's possible, e.g., // struct S1 { // struct { } S; // }; // Clang will translate struct { } S to // struct { // }; // struct S; // the last declaration is injected by clang. // We need to omit it. if (StartBuf > EndBuf) { SourceLocation KeywordLoc = Loc.getElaboratedKeywordLoc(); const llvm::StringRef Keyword = TypeWithKeyword::getKeywordName(ETy->getKeyword()); ConsumerInstance->TheRewriter.ReplaceText(KeywordLoc, Keyword.size(), "int"); return true; } ConsumerInstance->TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); return true; } bool EmptyStructToIntRewriteVisitor::VisitRecordDecl(RecordDecl *RD) { //if (ConsumerInstance->isSpecialRecordDecl(RD)) // return true; // Skip forward declarations const RecordDecl *RDDef = RD->getDefinition(); if (!RDDef) return true; // Skip the struct which will be deleted // It is already in the list if (RD->getCanonicalDecl() == ConsumerInstance->TheRecordDecl) { return true; } unsigned Idx = 0; for (RecordDecl::field_iterator I = RDDef->field_begin(), E = RDDef->field_end(); I != E; ++I) { const FieldDecl *FD = (*I); const Type *FDTy = FD->getType().getTypePtr(); const RecordDecl *BaseRD = ConsumerInstance->getBaseRecordDef(FDTy); // Handle all fields of struct type if (BaseRD) ConsumerInstance->handleOneRecordDecl(RDDef, BaseRD, FD, Idx); Idx++; } return true; } bool EmptyStructToIntRewriteVisitor::VisitVarDecl(VarDecl *VD) { if (!VD->hasInit()) { return true; } ConsumerInstance->handleOneVarDecl(VD); return true; } void EmptyStructToInt::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new EmptyStructToIntASTVisitor(this); RewriteVisitor = new EmptyStructToIntRewriteVisitor(this); } void EmptyStructToInt::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); removeRecordDecls(); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); // sanity check that we actually // have done some text modifications. // It could be false due to invalid code being transformed. if (!Rewritten) { TransError = TransNoTextModificationError; return; } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void EmptyStructToInt::handleOneRecordDecl(const RecordDecl *RD, const RecordDecl *BaseRD, const FieldDecl *FD, unsigned int Idx) { // Skip field if it is not of the type of one of // the structs that are affected by the change // Works recursively through chained structs if (!RecordDeclToField[BaseRD] && BaseRD != TheRecordDecl) { return; } IndexVector *NewIdxVec = RecordDeclToField[RD]; if (!NewIdxVec) { NewIdxVec = new IndexVector(); RecordDeclToField[RD] = NewIdxVec; } NewIdxVec->push_back(Idx); } void EmptyStructToInt::handleOneVarDecl(const VarDecl *VD) { const Type *Ty = VD->getType().getTypePtr(); const RecordDecl *RD = getBaseRecordDef(Ty); // Skip all variables which are not of struct type if (!RD) { return; } IndexVector *IdxVec = RecordDeclToField[RD]; // Skip variables for which the struct is not changed if (!IdxVec && RD != TheRecordDecl) { return; } ExprVector InitExprs; getInitExprs(Ty, VD->getInit(), IdxVec, InitExprs); for (ExprVector::iterator I = InitExprs.begin(), E = InitExprs.end(); I != E; ++I) { RewriteHelper->replaceExpr(*I, "0"); } } void EmptyStructToInt::doAnalysis(void) { for (RecordDeclSet::const_iterator I = VisitedRecordDecls.begin(), E = VisitedRecordDecls.end(); I != E; ++I) { const RecordDecl *RD = (*I); if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { if (BaseClassDecls.count(CXXRD->getCanonicalDecl())) continue; } ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) TheRecordDecl = RD; } } // ISSUE: we will have bad transformation for the case below: // typedef struct S; // S *s; // ==> // typedef // int *s; // This is bad because we don't catch the implicit declaration of struct S. // But hopefully peephole pass will remove the keyword typedef, // then we will be fine. void EmptyStructToInt::removeRecordDecls(void) { for (RecordDecl::redecl_iterator I = TheRecordDecl->redecls_begin(), E = TheRecordDecl->redecls_end(); I != E; ++I) { const RecordDecl *RD = dyn_cast(*I); SourceRange Range = RD->getSourceRange(); SourceLocation LocEnd = Range.getEnd(); SourceLocation SemiLoc = Lexer::findLocationAfterToken(LocEnd, tok::semi, *SrcManager, Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); // handle cases such as // struct S {} s; if (SemiLoc.isInvalid()) { if (!RD->isThisDeclarationADefinition()) return; SourceLocation RBLoc = RD->getBraceRange().getEnd(); if (RBLoc.isInvalid()) return; RewriteHelper->removeTextFromLeftAt(SourceRange(RBLoc, RBLoc), '{', RBLoc); Rewritten = true; } else { LocEnd = RewriteHelper->getEndLocationUntil(Range, ';'); TheRewriter.RemoveText(SourceRange(Range.getBegin(), LocEnd)); Rewritten = true; } } } bool EmptyStructToInt::pointToSelf(const FieldDecl *FD) { const Type *Ty = FD->getType().getTypePtr(); if (!Ty->isPointerType()) return false; const Type *PointeeTy = getBasePointerElemType(Ty); if (TransformationManager::isCXXLangOpt()) { const CXXRecordDecl *Base = getBaseDeclFromType(Ty); if (!Base) return false; const CXXRecordDecl *Parent = dyn_cast(FD->getParent()); TransAssert(Parent && "Invalid Parent!"); return (Parent->getCanonicalDecl() == Base->getCanonicalDecl()); } const RecordType *RT = PointeeTy->getAs(); if (!RT) return false; const RecordDecl *RD = RT->getDecl(); const RecordDecl *Parent = FD->getParent(); return (Parent->getCanonicalDecl() == RD->getCanonicalDecl()); } bool EmptyStructToInt::isValidRecordDecl(const RecordDecl *RD) { const CXXRecordDecl *CXXRD = dyn_cast(RD); if (!CXXRD) { const RecordDecl *Def = RD->getDefinition(); if (!Def) { return true; } else if (Def->field_empty()) { return true; } else { // skip invalid decl, which causes clang assertion errors if (Def->isInvalidDecl()) return false; // handle another special case where a struct has an unreferenced // field. In some cases, we cannot simply remove this field // because an empty struct would make a bug disappear. const ASTRecordLayout &Info = Context->getASTRecordLayout(Def); unsigned Count = Info.getFieldCount(); if (Count != 1) return false; const FieldDecl *FD = *(Def->field_begin()); TransAssert(FD && "Invalid FieldDecl"); // skip case such as // struct S { struct S *p; }; if (pointToSelf(FD)) return false; return !FD->isReferenced(); } } if (dyn_cast(CXXRD) || CXXRD->getDescribedClassTemplate() || CXXRD->getInstantiatedFromMemberClass()) return false; // It's possible that the described template does not // have definition, so we test hasDefinition after the // above `if' guard const CXXRecordDecl *CXXDef = CXXRD->getDefinition(); if (!CXXDef) return true; if(CXXDef->getNumBases()) return false; const DeclContext *Ctx = dyn_cast(CXXDef); TransAssert(Ctx && "Invalid DeclContext!"); int count = 0; for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if (!(*I)->isImplicit()) { if ((*I)->isReferenced()) return false; if (isa(*I) || isa(*I)) return false; if (const FunctionDecl *FD = dyn_cast(*I)) { if (FD->hasBody() && !FD->isInlined()) return false; } if (const FieldDecl *FieldD = dyn_cast(*I)) { if (pointToSelf(FieldD)) return false; } ++count; } } if (count > 1) return false; return true; } const RecordDecl *EmptyStructToInt::getBaseRecordDef(const Type *Ty) { const ArrayType *ArrayTy = dyn_cast(Ty); if (ArrayTy) { Ty = getArrayBaseElemType(ArrayTy); } if (!Ty->isStructureType()) return NULL; const RecordType *RT = Ty->getAsStructureType(); return RT->getDecl()->getDefinition(); } void EmptyStructToInt::getInitExprs(const Type *Ty, const Expr *E, const IndexVector *IdxVec, ExprVector &InitExprs) { const ArrayType *ArrayTy = dyn_cast(Ty); if (ArrayTy) { if (isa(E) || isa(E)) return; const InitListExpr *ILE = dyn_cast(E); TransAssert(ILE && "Invalid array initializer!"); unsigned int NumInits = ILE->getNumInits(); Ty = ArrayTy->getElementType().getTypePtr(); for (unsigned I = 0; I < NumInits; ++I) { const Expr *Init = ILE->getInit(I); getInitExprs(Ty, Init, IdxVec, InitExprs); } return; } const InitListExpr *ILE = dyn_cast(E); if (!ILE) return; const RecordType *RT = NULL; if (Ty->isUnionType()) { RT = Ty->getAsUnionType(); } else if (Ty->isStructureType()) { RT = Ty->getAsStructureType(); } else { TransAssert(0 && "Bad RecordType!"); } const RecordDecl *RD = RT->getDecl(); if (RD->getCanonicalDecl() == TheRecordDecl) { InitExprs.push_back(E); } else { for (IndexVector::const_iterator FI = IdxVec->begin(), FE = IdxVec->end(); FI != FE; ++FI) { const FieldDecl *FD = getFieldDeclByIdx(RD, (*FI)); TransAssert(FD && "NULL FieldDecl!"); Ty = FD->getType().getTypePtr(); const RecordDecl *BaseRD = getBaseRecordDef(Ty); unsigned int InitListIdx; if (BaseRD->isUnion()) { InitListIdx = 0; } else { InitListIdx = (*FI); } if (InitListIdx >= ILE->getNumInits()) { return; } getInitExprs(Ty, ILE->getInit(InitListIdx), RecordDeclToField[BaseRD], InitExprs); } } } const FieldDecl *EmptyStructToInt::getFieldDeclByIdx( const RecordDecl *RD, unsigned int Idx) { unsigned I = 0; for (RecordDecl::field_iterator RI = RD->field_begin(), RE = RD->field_end(); RI != RE; ++RI, ++I) { if (I == Idx) return (*RI); } return NULL; } bool EmptyStructToInt::isSourceRangeWithinRecordDecl(SourceRange Range, const RecordDecl *RD) { const char *StartBuf = SrcManager->getCharacterData(Range.getBegin()); const char *EndBuf = SrcManager->getCharacterData(Range.getEnd()); SourceRange RDRange = RD->getBraceRange(); const char *RDStartBuf = SrcManager->getCharacterData(RDRange.getBegin()); const char *RDEndBuf = SrcManager->getCharacterData(RDRange.getEnd()); return RDStartBuf < StartBuf && RDEndBuf > EndBuf; } EmptyStructToInt::~EmptyStructToInt(void) { delete CollectionVisitor; delete RewriteVisitor; for (RecordDeclToFieldIdxVectorMap::iterator I = RecordDeclToField.begin(), E = RecordDeclToField.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/EmptyStructToInt.h000066400000000000000000000055321402162750500205230ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef EMPTY_STRUCT_TO_INT_H #define EMPTY_STRUCT_TO_INT_H #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class RecordDecl; class FieldDecl; } class EmptyStructToIntASTVisitor; class EmptyStructToIntRewriteVisitor; class EmptyStructToInt : public Transformation { friend class EmptyStructToIntASTVisitor; friend class EmptyStructToIntRewriteVisitor; public: EmptyStructToInt(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheRecordDecl(NULL) { } ~EmptyStructToInt(void); private: typedef llvm::DenseMap RecordDeclToFieldIdxVectorMap; typedef llvm::SetVector RecordDeclSet; typedef llvm::SmallPtrSet CXXRecordDeclSet; typedef llvm::SmallPtrSet LocPtrSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneRecordDecl(const clang::RecordDecl *RD, const clang::RecordDecl *BaseRD, const clang::FieldDecl *FD, unsigned int Idx); void handleOneVarDecl(const clang::VarDecl *VD); bool isValidRecordDecl(const clang::RecordDecl *RD); bool pointToSelf(const clang::FieldDecl *FD); void removeRecordDecls(void); void doAnalysis(void); const clang::RecordDecl *getBaseRecordDef(const clang::Type *Ty); void getInitExprs(const clang::Type *Ty, const clang::Expr *E, const IndexVector *IdxVec, ExprVector &InitExprs); const clang::FieldDecl *getFieldDeclByIdx(const clang::RecordDecl *RD, unsigned int Idx); bool isSourceRangeWithinRecordDecl(clang::SourceRange Range, const clang::RecordDecl *RD); RecordDeclToFieldIdxVectorMap RecordDeclToField; RecordDeclSet VisitedRecordDecls; CXXRecordDeclSet BaseClassDecls; LocPtrSet VisitedLocs; EmptyStructToIntASTVisitor *CollectionVisitor; EmptyStructToIntRewriteVisitor *RewriteVisitor; const clang::RecordDecl *TheRecordDecl; // Unimplemented EmptyStructToInt(void); EmptyStructToInt(const EmptyStructToInt &); void operator=(const EmptyStructToInt &); }; #endif cvise-2.3.0/clang_delta/ExpressionDetector.cpp000066400000000000000000000523761402162750500214360ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ExpressionDetector.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" #include "CommonStatementVisitor.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Insert a printf statement to print out the value of an expression. \ Currently, only expressions of type integer and floating point are \ considered valid. The transformation also injects a static control \ variable to ensure that the expression of interest will be printed \ only once.\n"; // Some known issues: // (1) Because we don't have any array-bound analysis, this pass will // turn the following code into one that would coredump: // if (argc == 2 && !strcmp(argv[1], "xxx")) // ==> // int __cvise_expr_tmp_xxx = !strcmp(argv[1], "xxx"); // ... // (2) we don't perform pointer analysis, the transformed program // will produce different result from the original one, e.g., // int *x = &g; // foo((*x) += 1 || g); // ==> // int *x = &g; // int __cvise_expr_tmp_xxx = g; // ... // foo((*x) += 1 || __cvise_expr_tmp_xxx); static RegisterTransformation Trans("expression-detector", DescriptionMsg); namespace { class IncludesPPCallbacks : public PPCallbacks { public: IncludesPPCallbacks(SourceManager &M, const std::string &Name, bool &H, SourceLocation &Loc) : SrcManager(M), HeaderName(Name), HasHeader(H), HeaderLoc(Loc) { } virtual void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, StringRef SearchPath, StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) override; private: SourceManager &SrcManager; const std::string &HeaderName; bool &HasHeader; SourceLocation &HeaderLoc; }; void IncludesPPCallbacks::InclusionDirective(SourceLocation HashLoc, const Token &/*IncludeTok*/, StringRef FileName, bool /*IsAngled*/, CharSourceRange /*FilenameRange*/, const FileEntry * /*File*/, StringRef /*SearchPath*/, StringRef /*RelativePath*/, const Module * /*Imported*/, SrcMgr::CharacteristicKind /*FileType*/) { if (!SrcManager.isInMainFile(HashLoc)) return; // We may have multiple "#include ". Only handle the first one. if (!HasHeader && FileName == HeaderName) { HasHeader = true; HeaderLoc = HashLoc; } } // Collecting all tmp vars __cvise_expr_tmp_xxx within a statement // generated by C-Vise class LocalTmpVarCollector : public RecursiveASTVisitor { public: LocalTmpVarCollector(SmallVector &V, const std::string &P) : TmpVars(V), Prefix(P) { } bool VisitDeclRefExpr(DeclRefExpr *DRE); private: SmallVector &TmpVars; const std::string &Prefix; }; bool LocalTmpVarCollector::VisitDeclRefExpr(DeclRefExpr *DRE) { const VarDecl *VD = dyn_cast(DRE->getDecl()); if (!VD) return true; if (VD->getName().startswith(Prefix)) TmpVars.push_back(VD); return true; } // For a given statement, collect all expressions, each of which is // (1) either the sub-expression of an inc, dec or addrof operator; or // (2) the LHS of a binary operator; class LocalUOBOVisitor : public RecursiveASTVisitor { public: explicit LocalUOBOVisitor(llvm::SmallPtrSet &ES) : InvalidExprs(ES) { } bool VisitUnaryOperator(UnaryOperator *UO); bool VisitBinaryOperator(BinaryOperator *BO); private: llvm::SmallPtrSet &InvalidExprs; }; bool LocalUOBOVisitor::VisitUnaryOperator(UnaryOperator *UO) { if (!UO->isIncrementDecrementOp() && UO->getOpcode() != UO_AddrOf) return true; const Expr *E = UO->getSubExpr(); InvalidExprs.insert(E->IgnoreParenImpCasts()); return true; } bool LocalUOBOVisitor::VisitBinaryOperator(BinaryOperator *BO) { if (!BO->isAssignmentOp()) return true; const Expr *E = BO->getLHS(); InvalidExprs.insert(E->IgnoreParenImpCasts()); return true; } } // End anonymous namespace class ExprDetectorTempVarVisitor : public RecursiveASTVisitor { public: explicit ExprDetectorTempVarVisitor(ExpressionDetector *Instance) : ConsumerInstance(Instance) { } bool VisitDeclStmt(DeclStmt *DS); private: ExpressionDetector *ConsumerInstance; }; bool ExprDetectorTempVarVisitor::VisitDeclStmt(DeclStmt *DS) { for (auto I : DS->decls()) { ConsumerInstance->addOneTempVar(dyn_cast(I)); } return true; } class ExprDetectorCollectionVisitor : public RecursiveASTVisitor { public: explicit ExprDetectorCollectionVisitor(ExpressionDetector *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ExpressionDetector *ConsumerInstance; }; class ExprDetectorStmtVisitor : public CommonStatementVisitor { public: explicit ExprDetectorStmtVisitor(ExpressionDetector *Instance) : ConsumerInstance(Instance) { } bool VisitExpr(Expr *E); private: ExpressionDetector *ConsumerInstance; }; bool ExprDetectorCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (!ConsumerInstance->HFInfo.HasFunction && FD->getNameAsString() == ConsumerInstance->HFInfo.FunctionName) { ConsumerInstance->HFInfo.HasFunction = true; ConsumerInstance->HFInfo.FunctionLoc = FD->getSourceRange().getBegin(); } if (ConsumerInstance->isInIncludedFile(FD) || !FD->isThisDeclarationADefinition()) return true; ExprDetectorTempVarVisitor VarVisitor(ConsumerInstance); VarVisitor.TraverseDecl(FD); ExprDetectorStmtVisitor StmtVisitor(ConsumerInstance); StmtVisitor.setCurrentFunctionDecl(FD); StmtVisitor.TraverseDecl(FD); StmtVisitor.setCurrentFunctionDecl(NULL); ConsumerInstance->UniqueExprs.clear(); ConsumerInstance->ProcessedExprs.clear(); return true; } bool ExprDetectorStmtVisitor::VisitExpr(Expr *E) { if (ConsumerInstance->isInIncludedFile(E)) return true; switch(E->getStmtClass()) { default: return true; case Expr::ArraySubscriptExprClass: case Expr::BinaryOperatorClass: case Expr::CallExprClass: case Expr::DeclRefExprClass: case Expr::MemberExprClass: case Expr::UnaryOperatorClass: // Fall-through break; } const Type *Ty = E->getType().getTypePtr(); // Currently, integer and floating point only. if (!Ty->isIntegerType() && !Ty->isFloatingType()) return true; if (!ConsumerInstance->isValidExpr(CurrentStmt, E)) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheFunc = CurrentFuncDecl; ConsumerInstance->TheStmt = CurrentStmt; ConsumerInstance->TheExpr = E; } return true; } void ExpressionDetector::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ExprDetectorCollectionVisitor(this); if (CheckReference) { ControlVarNamePrefix = CheckedVarNamePrefix; HFInfo.HeaderName = "stdlib.h"; HFInfo.FunctionName = "abort"; HFInfo.FunctionDeclStr = "void abort(void)"; } else { ControlVarNamePrefix = PrintedVarNamePrefix; HFInfo.HeaderName = "stdio.h"; HFInfo.FunctionName = "printf"; HFInfo.FunctionDeclStr = "int printf(const char *format, ...)"; } ControlVarNameQueryWrap = new TransNameQueryWrap(ControlVarNamePrefix); TmpVarNameQueryWrap = new TransNameQueryWrap(TmpVarNamePrefix); Preprocessor &PP = TransformationManager::getPreprocessor(); IncludesPPCallbacks *C = new IncludesPPCallbacks(PP.getSourceManager(), HFInfo.HeaderName, HFInfo.HasHeader, HFInfo.HeaderLoc); PP.addPPCallbacks(std::unique_ptr(C)); } bool ExpressionDetector::HandleTopLevelDecl(DeclGroupRef D) { // Skip C++ programs for now. if (TransformationManager::isCXXLangOpt()) { ValidInstanceNum = 0; return true; } for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void ExpressionDetector::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFunc && "NULL TheFunc!"); TransAssert(TheStmt && "NULL TheStmt!"); TransAssert(TheExpr && "NULL TheExpr"); if (DoReplacement) { RewriteHelper->replaceExpr(TheExpr, Replacement); } else { ControlVarNameQueryWrap->TraverseDecl(TheFunc); TmpVarNameQueryWrap->TraverseDecl(TheFunc); doRewrite(); } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } // Return true if // (1) we don't have the function declaration or the decl appears after // the recorded FunctionLoc; and // (2) header file is not included in the main file or header file // appears after the Loc. bool ExpressionDetector::shouldAddFunctionDecl(SourceLocation Loc) { return (!HFInfo.HasFunction || SrcManager->isBeforeInSLocAddrSpace(Loc, HFInfo.FunctionLoc)) && (!HFInfo.HasHeader || SrcManager->isBeforeInSLocAddrSpace(Loc, HFInfo.HeaderLoc)); } void ExpressionDetector::addOneTempVar(const VarDecl *VD) { if (!VD) return; if (!VD->getName().startswith(TmpVarNamePrefix)) return; if (const Expr *E = VD->getInit()) ProcessedExprs[VD] = E->IgnoreParenImpCasts(); } bool ExpressionDetector::refToTmpVar(const NamedDecl *ND) { StringRef Name = ND->getName(); // We don't want to repeatly replace temporary variables // __cvise_expr_tmp_xxx, __cvise_printed_yy and __cvise_checked_zzz. return Name.startswith(TmpVarNamePrefix) || Name.startswith(PrintedVarNamePrefix) || Name.startswith(CheckedVarNamePrefix); } // Reference: IdenticalExprChecker.cpp from Clang bool ExpressionDetector::isIdenticalExpr(const Expr *E1, const Expr *E2) { if (!E1 || !E2) return !E1 && !E2; E1 = E1->IgnoreParenImpCasts(); E2 = E2->IgnoreParenImpCasts(); Stmt::StmtClass SC1 = E1->getStmtClass(); Stmt::StmtClass SC2 = E2->getStmtClass(); if (SC1 != SC2) return false; // If either of E1 or E2 has side-effects, treat them as non-identical // expressions. if (E1->HasSideEffects(*Context) || E2->HasSideEffects(*Context)) return false; Expr::const_child_iterator I1 = E1->child_begin(), I2 = E2->child_begin(); while (I1 != E1->child_end() && I2 != E2->child_end()) { if (!isIdenticalExpr(dyn_cast(*I1), dyn_cast(*I2))) return false; ++I1; ++I2; } if (I1 != E1->child_end() || I2 != E2->child_end()) return false; switch (SC1) { default: return false; case Stmt::ArraySubscriptExprClass: case Stmt::CallExprClass: // Fall-through return true; case Stmt::CStyleCastExprClass: { const CStyleCastExpr *Cast1 = cast(E1); const CStyleCastExpr *Cast2 = cast(E2); return Cast1->getTypeAsWritten() == Cast2->getTypeAsWritten(); } case Stmt::MemberExprClass: { const MemberExpr *ME1 = cast(E1); const MemberExpr *ME2 = cast(E2); return ME1->getMemberDecl() == ME2->getMemberDecl(); } case Stmt::DeclRefExprClass: { const DeclRefExpr *DRE1 = cast(E1); const DeclRefExpr *DRE2 = cast(E2); return DRE1->getDecl() == DRE2->getDecl(); } case Stmt::CompoundAssignOperatorClass: case Stmt::BinaryOperatorClass: // Fall-through { const BinaryOperator *BO1 = cast(E1); const BinaryOperator *BO2 = cast(E2); return BO1->getOpcode() == BO2->getOpcode(); } case Stmt::UnaryOperatorClass: { const UnaryOperator *UO1 = cast(E1); const UnaryOperator *UO2 = cast(E2); return UO1->getOpcode() == UO2->getOpcode(); } case Stmt::CharacterLiteralClass: { const CharacterLiteral *Lit1 = cast(E1); const CharacterLiteral *Lit2 = cast(E2); return Lit1->getValue() == Lit2->getValue(); } case Stmt::StringLiteralClass: { const clang::StringLiteral *Lit1 = cast(E1); const clang::StringLiteral *Lit2 = cast(E2); return Lit1->getBytes() == Lit2->getBytes(); } case Stmt::IntegerLiteralClass: { const IntegerLiteral *Lit1 = cast(E1); const IntegerLiteral *Lit2 = cast(E2); llvm::APInt I1 = Lit1->getValue(); llvm::APInt I2 = Lit2->getValue(); return I1.getBitWidth() == I2.getBitWidth() && I1 == I2; } case Stmt::FloatingLiteralClass: { const FloatingLiteral *Lit1 = cast(E1); const FloatingLiteral *Lit2 = cast(E2); return Lit1->getValue().bitwiseIsEqual(Lit2->getValue()); } } return true; } bool ExpressionDetector::hasIdenticalExpr( const SmallVector &TmpVars, const Expr *E) { for (auto V : TmpVars) { auto I = ProcessedExprs.find(V); if (I != ProcessedExprs.end() && isIdenticalExpr(I->second, E)) return true; } return false; } bool ExpressionDetector::isValidExpr(Stmt *S, const Expr *E) { Stmt::StmtClass SC = S->getStmtClass(); // Don't mess up with init/condition/inc exprs of loops. if (SC == Stmt::ForStmtClass || SC == Stmt::DoStmtClass || SC == Stmt::WhileStmtClass) { return false; } if (const Expr *SE = dyn_cast(S)) { // Don't do self-replacement. Note that E can't be of paren // or cast expr (See ExprDetectorStmtVisitor::VisitExpr). if (SE->IgnoreParenCasts() == E) return false; } if (const DeclStmt *DS = dyn_cast(S)) { if (DS->isSingleDecl()) { const NamedDecl *ND = dyn_cast(DS->getSingleDecl()); if (ND == NULL || refToTmpVar(ND)) return false; } else { // Skip group decls for now. return false; } } // don't handle !__cvise_printed and !__cvise_checked if (const UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() == UO_LNot) { if (const DeclRefExpr *SubE = dyn_cast(UO->getSubExpr()->IgnoreParenCasts())) { StringRef SubEName = SubE->getDecl()->getName(); if (SubEName.startswith(PrintedVarNamePrefix) || SubEName.startswith(CheckedVarNamePrefix)) return false; } } } // skip if (__cvise_expr_tmp != xxx) if (const BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_NE) { const Expr *Lhs = BO->getLHS()->IgnoreParenCasts(); const Expr *Rhs = BO->getRHS()->IgnoreParenCasts(); const DeclRefExpr *DRE = dyn_cast(Lhs); Stmt::StmtClass SC = Rhs->getStmtClass(); bool IsLit = SC == Stmt::IntegerLiteralClass || SC == Stmt::FloatingLiteralClass; if (IsLit && DRE && DRE->getDecl()->getName().startswith(TmpVarNamePrefix) && S->getStmtClass() == Stmt::IfStmtClass) { return false; } } } if (const DeclRefExpr *DRE = dyn_cast(E)) { // Don't repeatly process temp vars. if (refToTmpVar(DRE->getDecl())) return false; // Skip cases such as printf("%d", a); if (const CallExpr *CE = dyn_cast(S)) { const FunctionDecl *FD = CE->getDirectCallee(); if (FD && FD->getNameAsString() == "printf") return false; } } // If the Expr is the LHS of a binary operator, we don't // need to process it, e.g., given // a = x + y; // we don't need to replace "a" with "__cvise_expr_tmp_xxx" // // We also skip x++, --x and &x, because we don't want to make // the following transformation: // x++; // ==> // __cvise_expr_tmp_xxx = x; // ++__cvise_expr_tmp_xxx; // In the original code, we pre-increment x, but after the "transformation", // we would end up doing that for __cvise_expr_tmp_xxx. // Note that we cache the result, because we don't want to re-visit the same // statement many times. Gain a log of performance improvement. auto EI = InvalidExprsInUOBO.find(S); if (EI == InvalidExprsInUOBO.end()) { llvm::SmallPtrSet InvalidExprs; LocalUOBOVisitor UOBOVisitor(InvalidExprs); UOBOVisitor.TraverseStmt(S); InvalidExprsInUOBO[S] = InvalidExprs; if (InvalidExprs.count(E)) return false; } else if (EI->second.count(E)) { return false; } // Skip identical expression. For example, for // the given statement below: // x = y[1] + y[1] + y[1]; // we only need to print one y[1] before the assignment statement. // This optimization is able to avoid a lots of dups. auto &Vec = UniqueExprs[S]; for (auto I : Vec) { if (isIdenticalExpr(I, E)) return false; } // update UniqueExprs Vec.push_back(E); // The optimization above only works for single iteration. The code // below handles the following patterns: // int __cvise_expr_tmp_1 = y[1]; // ...printf("%d\n", __cvise_expr_tmp_1); // x = __cvise_expr_tmp_1 + y[1] + y[1] // We don't need to generate another tmp var for y[1] in this case. auto VI = TmpVarsInStmt.find(S); if (VI == TmpVarsInStmt.end()) { SmallVector TmpVars; LocalTmpVarCollector TmpCollector(TmpVars, TmpVarNamePrefix); TmpCollector.TraverseStmt(S); TmpVarsInStmt[S] = TmpVars; if (hasIdenticalExpr(TmpVars, E)) return false; } else if (hasIdenticalExpr(VI->second, E)) { return false; } return true; } static std::string getFormatString(const BuiltinType *BT) { switch(BT->getKind()) { default: TransAssert(0 && "Bad BuiltinType!"); return ""; case BuiltinType::Bool: case BuiltinType::Char_U: case BuiltinType::WChar_U: case BuiltinType::UChar: case BuiltinType::UShort: case BuiltinType::UInt: return "u"; case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::WChar_S: case BuiltinType::Short: case BuiltinType::Int: case BuiltinType::Char16: case BuiltinType::Char32: return "d"; case BuiltinType::ULong: return "lu"; case BuiltinType::Long: return "ld"; case BuiltinType::ULongLong: return "llu"; case BuiltinType::LongLong: return "lld"; case BuiltinType::Float: case BuiltinType::Double: return "f"; case BuiltinType::LongDouble: return "Lf"; } return ""; } void ExpressionDetector::doRewrite() { SourceLocation LocStart = TheStmt->getBeginLoc(); if (shouldAddFunctionDecl(LocStart)) { SourceLocation Loc = SrcManager->getLocForStartOfFile(SrcManager->getMainFileID()); TheRewriter.InsertText(Loc, HFInfo.FunctionDeclStr+";\n"); } std::string Str, ExprStr, TmpVarName; RewriteHelper->getExprString(TheExpr, ExprStr); std::string TyStr; TheExpr->getType().getAsStringInternal(TyStr, Context->getPrintingPolicy()); TmpVarName = TmpVarNamePrefix + std::to_string(TmpVarNameQueryWrap->getMaxNamePostfix()+1); Str += TyStr + " " + TmpVarName + " = " + ExprStr + ";\n"; std::string ControlVarName = ControlVarNamePrefix + std::to_string(ControlVarNameQueryWrap->getMaxNamePostfix()+1); Str += "static int " + ControlVarName + " = 0;\n"; Str += "if (" + ControlVarName + " == __CVISE_INSTANCE_NUMBER) {\n"; if (CheckReference) { Str += " if (" + TmpVarName + " != " + ReferenceValue + ") "; Str += HFInfo.FunctionName + "();\n"; } else { const Type *Ty = TheExpr->getType().getTypePtr()->getUnqualifiedDesugaredType(); std::string FormatStr = getFormatString(dyn_cast(Ty)); Str += " " + HFInfo.FunctionName; Str += "(\"cvise_value(%" + FormatStr + ")\\n\", "; Str += TmpVarName + ");\n"; } Str += "}\n"; Str += "++" + ControlVarName + ";"; bool NeedParen = TheStmt->getStmtClass() != Stmt::DeclStmtClass; RewriteHelper->addStringBeforeStmtAndReplaceExpr(TheStmt, Str, TheExpr, TmpVarName, NeedParen); } ExpressionDetector::~ExpressionDetector(void) { delete CollectionVisitor; delete ControlVarNameQueryWrap; delete TmpVarNameQueryWrap; } cvise-2.3.0/clang_delta/ExpressionDetector.h000066400000000000000000000066701402162750500210770ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef EXPRESSION_DETECTOR_H #define EXPRESSION_DETECTOR_H #include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "clang/Basic/SourceLocation.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class NamedDecl; class VarDecl; class Stmt; class Expr; } class ExprDetectorCollectionVisitor; class ExpressionDetector : public Transformation { friend class ExprDetectorCollectionVisitor; friend class ExprDetectorStmtVisitor; friend class ExprDetectorTempVarVisitor; public: ExpressionDetector(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), ControlVarNameQueryWrap(NULL), TmpVarNameQueryWrap(NULL), TheFunc(NULL), TheStmt(NULL), TheExpr(NULL), PrintedVarNamePrefix("__cvise_printed_"), CheckedVarNamePrefix("__cvise_checked_"), ControlVarNamePrefix(""), TmpVarNamePrefix("__cvise_expr_tmp_") { } ~ExpressionDetector(void); private: struct HeaderFunctionInfo { HeaderFunctionInfo () : HasHeader(false), HasFunction(false) { } bool HasHeader; bool HasFunction; clang::SourceLocation HeaderLoc; clang::SourceLocation FunctionLoc; std::string HeaderName; std::string FunctionName; std::string FunctionDeclStr; }; typedef std::vector ExprVector; typedef std::map StmtToExprMap; typedef std::map > StmtToExprSetMap; typedef std::map > StmtToVarVecMap; typedef llvm::DenseMap VarToExprMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addOneTempVar(const clang::VarDecl *VD); bool refToTmpVar(const clang::NamedDecl *ND); bool isValidExpr(clang::Stmt *S, const clang::Expr *E); void doRewrite(); bool shouldAddFunctionDecl(clang::SourceLocation Loc); bool isIdenticalExpr(const clang::Expr *E1, const clang::Expr *E2); bool hasIdenticalExpr( const llvm::SmallVector &TmpVars, const clang::Expr *E); StmtToExprMap UniqueExprs; VarToExprMap ProcessedExprs; StmtToExprSetMap InvalidExprsInUOBO; StmtToVarVecMap TmpVarsInStmt; ExprDetectorCollectionVisitor *CollectionVisitor; TransNameQueryWrap *ControlVarNameQueryWrap; TransNameQueryWrap *TmpVarNameQueryWrap; clang::FunctionDecl *TheFunc; clang::Stmt *TheStmt; clang::Expr *TheExpr; std::string PrintedVarNamePrefix; std::string CheckedVarNamePrefix; std::string ControlVarNamePrefix; std::string TmpVarNamePrefix; HeaderFunctionInfo HFInfo; // Unimplemented ExpressionDetector(void); ExpressionDetector(const ExpressionDetector &); void operator=(const ExpressionDetector &); }; #endif // EXPRESSION_DETECTOR_H cvise-2.3.0/clang_delta/InstantiateTemplateParam.cpp000066400000000000000000000311741402162750500225360ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "InstantiateTemplateParam.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass tries to instantiate a template parameter with \ its actual argument if this parameter has been instantiated \n\ only once. \n"; static RegisterTransformation Trans("instantiate-template-param", DescriptionMsg); namespace { typedef llvm::SmallPtrSet TemplateParameterSet; class TemplateParameterVisitor : public RecursiveASTVisitor { public: explicit TemplateParameterVisitor(TemplateParameterSet &Params) : UsedParameters(Params) { } ~TemplateParameterVisitor() { }; bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc Loc); private: TemplateParameterSet &UsedParameters; }; // seems clang can't detect the T in T::* in the following case: // struct B; // template struct C { // C(void (T::*)()) { } // }; // struct D { C m; }; bool TemplateParameterVisitor::VisitTemplateTypeParmTypeLoc( TemplateTypeParmTypeLoc Loc) { const TemplateTypeParmDecl *D = Loc.getDecl(); UsedParameters.insert(D); return true; } } // end anonymous namespace class InstantiateTemplateParamASTVisitor : public RecursiveASTVisitor { public: explicit InstantiateTemplateParamASTVisitor( InstantiateTemplateParam *Instance) : ConsumerInstance(Instance) { } bool VisitRecordDecl(RecordDecl *D); bool VisitClassTemplateDecl(ClassTemplateDecl *D); bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); private: InstantiateTemplateParam *ConsumerInstance; }; bool InstantiateTemplateParamASTVisitor::VisitRecordDecl(RecordDecl *D) { ConsumerInstance->AvailableRecordDecls.insert( dyn_cast(D->getCanonicalDecl())); return true; } bool InstantiateTemplateParamASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneClassTemplateDecl(D); return true; } bool InstantiateTemplateParamASTVisitor::VisitFunctionTemplateDecl( FunctionTemplateDecl *D) { if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneFunctionTemplateDecl(D); return true; } class InstantiateTemplateParamRewriteVisitor : public RecursiveASTVisitor { public: explicit InstantiateTemplateParamRewriteVisitor( InstantiateTemplateParam *Instance) : ConsumerInstance(Instance) { } bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc Loc); private: InstantiateTemplateParam *ConsumerInstance; }; bool InstantiateTemplateParamRewriteVisitor::VisitTemplateTypeParmTypeLoc( TemplateTypeParmTypeLoc Loc) { const TemplateTypeParmDecl *D = Loc.getDecl(); if (D != ConsumerInstance->TheParameter) return true; // I know it's ugly, but seems sometimes Clang injects some extra // TypeLoc which causes the problem, for example, in the code below, // template class A { // public: // template struct C { typedef A other; }; // }; // template class B { // typedef typename T2::template C::other type; // }; // class B >; // the "typedef typename T2 ..." is treated as // typedef typename T2::template T2::C::other type; // where the second T2 is injected by Clang void *Ptr = Loc.getBeginLoc().getPtrEncoding(); if (ConsumerInstance->VisitedLocs.count(Ptr)) return true; ConsumerInstance->VisitedLocs.insert(Ptr); SourceRange Range = Loc.getSourceRange(); ConsumerInstance->TheRewriter.ReplaceText(Range, ConsumerInstance->TheInstantiationString); return true; } void InstantiateTemplateParam::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new InstantiateTemplateParamASTVisitor(this); ParamRewriteVisitor = new InstantiateTemplateParamRewriteVisitor(this); } void InstantiateTemplateParam::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheParameter && "NULL TheParameter!"); TransAssert((TheInstantiationString != "") && "Invalid InstantiationString!"); TransAssert(ParamRewriteVisitor && "NULL ParamRewriteVisitor!"); ParamRewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); removeTemplateKeyword(); addForwardDecl(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void InstantiateTemplateParam::removeTemplateKeyword() { if (dyn_cast(TheTemplateDecl)) return; TemplateParameterList *TPList = TheTemplateDecl->getTemplateParameters(); if (TPList->size() != 1) return; const NamedDecl *ND = TPList->getParam(0); (void)ND; TransAssert((ND == TheParameter) && "Invalid template parameter!"); TheRewriter.RemoveText(SourceRange(TPList->getTemplateLoc(), TPList->getRAngleLoc())); } void InstantiateTemplateParam::addForwardDecl() { TransAssert(TheTemplateDecl && "NULL TheTemplateDecl!"); if (TheForwardDeclString == "") return; RewriteHelper->insertStringBeforeTemplateDecl(TheTemplateDecl, TheForwardDeclString); } void InstantiateTemplateParam::addOneForwardDeclStr( const RecordDecl *RD, std::string &ForwardStr, RecordDeclSet &TempAvailableRecordDecls) { const RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); if (AvailableRecordDecls.count(CanonicalRD) || TempAvailableRecordDecls.count(CanonicalRD)) return; ForwardStr += RD->getKindName(); ForwardStr += " "; ForwardStr += RD->getNameAsString() + ";\n"; TempAvailableRecordDecls.insert(CanonicalRD); } void InstantiateTemplateParam::addForwardTemplateDeclStr( const ClassTemplateDecl *ClassTD, std::string &ForwardStr, RecordDeclSet &TempAvailableRecordDecls) { const CXXRecordDecl *RD = ClassTD->getTemplatedDecl(); const RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); if (AvailableRecordDecls.count(CanonicalRD) || TempAvailableRecordDecls.count(CanonicalRD)) return; std::string TemplateStr = ""; RewriteHelper->getStringBetweenLocs(TemplateStr, ClassTD->getSourceRange().getBegin(), RD->getInnerLocStart()); ForwardStr += TemplateStr; ForwardStr += RD->getKindName(); ForwardStr += " "; ForwardStr += RD->getNameAsString() + ";\n"; TempAvailableRecordDecls.insert(CanonicalRD); } void InstantiateTemplateParam::getForwardDeclStr( const Type *Ty, std::string &ForwardStr, RecordDeclSet &TempAvailableRecordDecls) { if (const RecordType *RT = Ty->getAsUnionType()) { const RecordDecl *RD = RT->getDecl(); addOneForwardDeclStr(RD, ForwardStr, TempAvailableRecordDecls); return; } const CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl(); if (!CXXRD) return; const ClassTemplateSpecializationDecl *SpecD = dyn_cast(CXXRD); if (!SpecD) { addOneForwardDeclStr(CXXRD, ForwardStr, TempAvailableRecordDecls); return; } addForwardTemplateDeclStr(SpecD->getSpecializedTemplate(), ForwardStr, TempAvailableRecordDecls); const TemplateArgumentList &ArgList = SpecD->getTemplateArgs(); unsigned NumArgs = ArgList.size(); for (unsigned I = 0; I < NumArgs; ++I) { const TemplateArgument Arg = ArgList[I]; if (Arg.getKind() != TemplateArgument::Type) continue; getForwardDeclStr(Arg.getAsType().getTypePtr(), ForwardStr, TempAvailableRecordDecls); } } bool InstantiateTemplateParam::getTypeString( const QualType &QT, std::string &Str, std::string &ForwardStr) { const Type *Ty = QT.getTypePtr(); Type::TypeClass TC = Ty->getTypeClass(); switch (TC) { case Type::Elaborated: { const ElaboratedType *ETy = dyn_cast(Ty); return getTypeString(ETy->getNamedType(), Str, ForwardStr); } case Type::Typedef: { const TypedefType *TdefTy = dyn_cast(Ty); const TypedefNameDecl *TdefD = TdefTy->getDecl(); return getTypeString(TdefD->getUnderlyingType(), Str, ForwardStr); } case Type::Record: { RecordDeclSet TempAvailableRecordDecls; getForwardDeclStr(Ty, ForwardStr, TempAvailableRecordDecls); QT.getAsStringInternal(Str, Context->getPrintingPolicy()); return true; } case Type::Builtin: { QT.getAsStringInternal(Str, Context->getPrintingPolicy()); return true; } default: return false; } TransAssert(0 && "Unreachable code!"); return false; } bool InstantiateTemplateParam::getTemplateArgumentString(const TemplateArgument &Arg, std::string &ArgStr, std::string &ForwardStr) { ArgStr = ""; ForwardStr = ""; if (Arg.getKind() != TemplateArgument::Type) return false; QualType QT = Arg.getAsType(); return getTypeString(QT, ArgStr, ForwardStr); } void InstantiateTemplateParam::handleOneTemplateSpecialization( const TemplateDecl *D, const TemplateArgumentList & ArgList) { if (isInIncludedFile(D)) return; NamedDecl *ND = D->getTemplatedDecl(); TemplateParameterSet ParamsSet; TemplateParameterVisitor ParameterVisitor(ParamsSet); ParameterVisitor.TraverseDecl(ND); if (ParamsSet.size() == 0) return; unsigned NumArgs = ArgList.size(); (void)NumArgs; unsigned Idx = 0; TemplateParameterList *TPList = D->getTemplateParameters(); for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ND = (*I); // make it simple, skip NonTypeTemplateParmDecl and // TemplateTemplateParmDecl for now const TemplateTypeParmDecl *TyParmDecl = dyn_cast(ND); if (!TyParmDecl || TyParmDecl->isParameterPack() || !ParamsSet.count(ND)) { Idx++; continue; } TransAssert((Idx < NumArgs) && "Invalid Idx!"); const TemplateArgument &Arg = ArgList.get(Idx); std::string ArgStr; std::string ForwardStr; if (!getTemplateArgumentString(Arg, ArgStr, ForwardStr)) continue; // in case the argument has the same name as the parameter if (ArgStr == ND->getNameAsString()) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheInstantiationString = ArgStr; TheParameter = ND; TheTemplateDecl = D; TheForwardDeclString = ForwardStr; } } } // TODO: handle partial specialization void InstantiateTemplateParam::handleOneClassTemplateDecl( const ClassTemplateDecl *D) { ClassTemplateDecl::spec_iterator I = D->spec_begin(); ClassTemplateDecl::spec_iterator E = D->spec_end(); if (I == E) return; ClassTemplateSpecializationDecl *SpecD = (*I); ++I; if (I != D->spec_end()) return; handleOneTemplateSpecialization(D, SpecD->getTemplateArgs()); } void InstantiateTemplateParam::handleOneFunctionTemplateDecl( const FunctionTemplateDecl *D) { FunctionTemplateDecl::spec_iterator I = D->spec_begin(); FunctionTemplateDecl::spec_iterator E = D->spec_end(); if (I == E) return; const FunctionDecl *FD = (*I); ++I; if (I != D->spec_end()) return; if (const FunctionTemplateSpecializationInfo *Info = FD->getTemplateSpecializationInfo()) { handleOneTemplateSpecialization(D, *(Info->TemplateArguments)); } } InstantiateTemplateParam::~InstantiateTemplateParam() { delete CollectionVisitor; delete ParamRewriteVisitor; } cvise-2.3.0/clang_delta/InstantiateTemplateParam.h000066400000000000000000000064421402162750500222030ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef INSTANTIATE_TEMPLATE_PARAM_H #define INSTANTIATE_TEMPLATE_PARAM_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionTemplateDecl; class ClassTemplateDecl; class TemplateDecl; class TemplateArgumentList; class TemplateArgument; class QualType; class NamedDecl; class Type; class RecordDecl; } class InstantiateTemplateParamASTVisitor; class InstantiateTemplateParamRewriteVisitor; class InstantiateTemplateParam : public Transformation { friend class InstantiateTemplateParamASTVisitor; friend class InstantiateTemplateParamRewriteVisitor; public: InstantiateTemplateParam(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), ParamRewriteVisitor(NULL), TheParameter(NULL), TheTemplateDecl(NULL), TheInstantiationString(""), TheForwardDeclString("") {} ~InstantiateTemplateParam(); private: typedef llvm::SmallPtrSet RecordDeclSet; typedef llvm::SmallPtrSet LocPtrSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneFunctionTemplateDecl(const clang::FunctionTemplateDecl *D); void handleOneClassTemplateDecl(const clang::ClassTemplateDecl *D); void handleOneTemplateSpecialization( const clang::TemplateDecl *D, const clang::TemplateArgumentList & ArgList); bool getTemplateArgumentString(const clang::TemplateArgument &Arg, std::string &Str, std::string &ForwardStr); bool getTypeString(const clang::QualType &QT, std::string &ArgStr, std::string &ForwardStr); void getForwardDeclStr(const clang::Type *Ty, std::string &ForwardStr, RecordDeclSet &TempAvailableRecordDecls); void addOneForwardDeclStr(const clang::RecordDecl *RD, std::string &ForwardStr, RecordDeclSet &TempAvailableRecordDecls); void addForwardTemplateDeclStr(const clang::ClassTemplateDecl *ClassTD, std::string &ForwardStr, RecordDeclSet &TempAvailableRecordDecls); void removeTemplateKeyword(); void addForwardDecl(); RecordDeclSet AvailableRecordDecls; LocPtrSet VisitedLocs; InstantiateTemplateParamASTVisitor *CollectionVisitor; InstantiateTemplateParamRewriteVisitor *ParamRewriteVisitor; const clang::NamedDecl *TheParameter; const clang::TemplateDecl *TheTemplateDecl; std::string TheInstantiationString; std::string TheForwardDeclString; // Unimplemented InstantiateTemplateParam(); InstantiateTemplateParam(const InstantiateTemplateParam &); void operator=(const InstantiateTemplateParam &); }; #endif cvise-2.3.0/clang_delta/InstantiateTemplateTypeParamToInt.cpp000066400000000000000000000206411402162750500243530ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "InstantiateTemplateTypeParamToInt.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; // TODO: probably need to handle more cases where this transformation // generates invalid code, e.g.: // template struct S { // typedef T type; // type &foo(); // }; // struct A { // void foo() {}; // }; // void bar() { // struct S s; // struct A a = s.foo(); // } static const char *DescriptionMsg = "This pass tries to instantiate a template type parameter of a class \ inside the class's definition. For example, \n\ template struct A { T foo(void); } \n\ => \n\ template struct A { int foo(void); } \n\ \n\ Currently, just simply replace any reference of T with int.\n"; static RegisterTransformation Trans("instantiate-template-type-param-to-int", DescriptionMsg); namespace { typedef llvm::SmallPtrSet TemplateParameterSet; class TemplateParameterVisitor : public RecursiveASTVisitor { public: explicit TemplateParameterVisitor(TemplateParameterSet &Params) : UsedParameters(Params) { } ~TemplateParameterVisitor() { }; bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc Loc); private: TemplateParameterSet &UsedParameters; }; // seems clang can't detect the T in T::* in the following case: // struct B; // template struct C { // C(void (T::*)()) { } // }; // struct D { C m; }; bool TemplateParameterVisitor::VisitTemplateTypeParmTypeLoc( TemplateTypeParmTypeLoc Loc) { const TemplateTypeParmDecl *D = Loc.getDecl(); UsedParameters.insert(D); return true; } } // end anonymous namespace // In order to generate less uncompilable code, filter out cases such as // template struct S { // T::type foo(void); // }; class TemplateParameterFilterVisitor : public RecursiveASTVisitor { public: TemplateParameterFilterVisitor(TemplateParameterSet &Params, InstantiateTemplateTypeParamToInt *Instance) : Parameters(Params), ConsumerInstance(Instance) { } ~TemplateParameterFilterVisitor() { }; bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc Loc); private: TemplateParameterSet &Parameters; InstantiateTemplateTypeParamToInt *ConsumerInstance; }; bool TemplateParameterFilterVisitor::VisitTemplateTypeParmTypeLoc( TemplateTypeParmTypeLoc Loc) { const NamedDecl *ND = Loc.getDecl(); if (!Parameters.count(ND)) return true; if (ConsumerInstance->isBeforeColonColon(Loc)) Parameters.erase(ND); return true; } // ISSUE: maybe also try to instantiate a type parm with // its default value, if it exists? class InstantiateTemplateTypeParamToIntASTVisitor : public RecursiveASTVisitor { public: explicit InstantiateTemplateTypeParamToIntASTVisitor( InstantiateTemplateTypeParamToInt *Instance) : ConsumerInstance(Instance) { } bool VisitClassTemplateDecl(ClassTemplateDecl *D); bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); private: InstantiateTemplateTypeParamToInt *ConsumerInstance; }; class InstantiateTemplateTypeParamToIntRewriteVisitor : public RecursiveASTVisitor { public: explicit InstantiateTemplateTypeParamToIntRewriteVisitor( InstantiateTemplateTypeParamToInt *Instance) : ConsumerInstance(Instance) { } bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc Loc); private: InstantiateTemplateTypeParamToInt *ConsumerInstance; }; bool InstantiateTemplateTypeParamToIntASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { // only care about declarations if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneTemplateDecl(D); return true; } bool InstantiateTemplateTypeParamToIntASTVisitor::VisitFunctionTemplateDecl( FunctionTemplateDecl *D) { // only care about declarations if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneTemplateDecl(D); return true; } bool InstantiateTemplateTypeParamToIntRewriteVisitor::VisitTemplateTypeParmTypeLoc( TemplateTypeParmTypeLoc Loc) { const TemplateTypeParmDecl *D = Loc.getDecl(); if (D != ConsumerInstance->TheParameter) return true; void *Ptr = Loc.getBeginLoc().getPtrEncoding(); if (ConsumerInstance->VisitedLocs.count(Ptr)) return true; ConsumerInstance->VisitedLocs.insert(Ptr); SourceRange Range = Loc.getSourceRange(); ConsumerInstance->TheRewriter.ReplaceText(Range, "int"); return true; } void InstantiateTemplateTypeParamToInt::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new InstantiateTemplateTypeParamToIntASTVisitor(this); ParamRewriteVisitor = new InstantiateTemplateTypeParamToIntRewriteVisitor(this); } void InstantiateTemplateTypeParamToInt::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheParameter && "NULL TheParameter!"); TransAssert(ParamRewriteVisitor && "NULL ParamRewriteVisitor!"); ParamRewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void InstantiateTemplateTypeParamToInt::handleOneTemplateDecl(const TemplateDecl *D) { if (isInIncludedFile(D)) return; // doesn't handle TypeAliasTemplateDecl TransAssert((!dyn_cast(D)) && "Doesn't support TypeAliasTemplateDecl!"); const TemplateDecl *CanonicalD = dyn_cast(D->getCanonicalDecl()); TransAssert(CanonicalD && "Invalid TemplateDecl!"); TransAssert((VisitedTemplateDecls.count(CanonicalD) == 0) && "Duplicate visitation to TemplateDecl!"); VisitedTemplateDecls.insert(CanonicalD); NamedDecl *ND = D->getTemplatedDecl(); TemplateParameterSet ParamsSet; TemplateParameterVisitor ParameterVisitor(ParamsSet); ParameterVisitor.TraverseDecl(ND); filterInvalidParams(D, ParamsSet); if (ParamsSet.size() == 0) return; TemplateParameterList *TPList = D->getTemplateParameters(); for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ND = (*I); if (!ParamsSet.count(ND)) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) TheParameter = ND; } } void InstantiateTemplateTypeParamToInt::filterInvalidParams(const TemplateDecl *D, TemplateParameterSet &Params) { NamedDecl *ND = D->getTemplatedDecl(); TemplateParameterFilterVisitor Filter(Params, this); Filter.TraverseDecl(ND); const ClassTemplateDecl *CD = dyn_cast(D); if (!CD) return; CXXRecordDecl *Def = CD->getTemplatedDecl()->getDefinition(); TransAssert(Def && "No Definition?"); if (!Def->isCompleteDefinition()) return; for (CXXRecordDecl::base_class_const_iterator I = Def->bases_begin(), E = Def->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const TemplateTypeParmType *ParmTy = dyn_cast(Ty); if (!ParmTy) continue; const TemplateTypeParmDecl *ParmD = ParmTy->getDecl(); Params.erase(ParmD); } } InstantiateTemplateTypeParamToInt::~InstantiateTemplateTypeParamToInt() { delete CollectionVisitor; delete ParamRewriteVisitor; } cvise-2.3.0/clang_delta/InstantiateTemplateTypeParamToInt.h000066400000000000000000000042421402162750500240170ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef INSTANTIATE_TEMPLATE_TYPE_PARAM_TO_INT_H #define INSTANTIATE_TEMPLATE_TYPE_PARAM_TO_INT_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class TemplateDecl; class NamedDecl; } class InstantiateTemplateTypeParamToIntASTVisitor; class InstantiateTemplateTypeParamToIntRewriteVisitor; class InstantiateTemplateTypeParamToInt : public Transformation { friend class InstantiateTemplateTypeParamToIntASTVisitor; friend class InstantiateTemplateTypeParamToIntRewriteVisitor; friend class TemplateParameterFilterVisitor; public: InstantiateTemplateTypeParamToInt(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), ParamRewriteVisitor(NULL), TheParameter(NULL) {} ~InstantiateTemplateTypeParamToInt(); private: typedef llvm::SmallPtrSet TemplateDeclSet; typedef llvm::SmallPtrSet TemplateParameterSet; typedef llvm::SmallPtrSet LocPtrSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneTemplateDecl(const clang::TemplateDecl *D); void filterInvalidParams(const clang::TemplateDecl *D, TemplateParameterSet &Params); TemplateDeclSet VisitedTemplateDecls; LocPtrSet VisitedLocs; InstantiateTemplateTypeParamToIntASTVisitor *CollectionVisitor; InstantiateTemplateTypeParamToIntRewriteVisitor *ParamRewriteVisitor; const clang::NamedDecl *TheParameter; // Unimplemented InstantiateTemplateTypeParamToInt(); InstantiateTemplateTypeParamToInt(const InstantiateTemplateTypeParamToInt &); void operator=(const InstantiateTemplateTypeParamToInt &); }; #endif cvise-2.3.0/clang_delta/LiftAssignmentExpr.cpp000066400000000000000000000151701402162750500213620ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "LiftAssignmentExpr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonStatementVisitor.h" using namespace clang; static const char *DescriptionMsg = "Lift an assignment expression to an assignment statement. \ An assignment expression will be lifted if it apprears at : \n\ * the guard position of an if, while or do statement; \n\ * function argument; \n\ * init, condition or inc position of a for statement \n"; static RegisterTransformation Trans("lift-assignment-expr", DescriptionMsg); class AssignExprCollectionVisitor : public RecursiveASTVisitor { public: explicit AssignExprCollectionVisitor(LiftAssignmentExpr *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: LiftAssignmentExpr *ConsumerInstance; }; class AssignExprStatementVisitor : public CommonStatementVisitor { public: explicit AssignExprStatementVisitor(LiftAssignmentExpr *Instance) : ConsumerInstance(Instance) { } bool VisitIfStmt(IfStmt *IS); bool VisitForStmt(ForStmt *FS); bool VisitWhileStmt(WhileStmt *WS); bool VisitDoStmt(DoStmt *DS); bool VisitCallExpr(CallExpr *CallE); private: LiftAssignmentExpr *ConsumerInstance; void handleSubExpr(Expr *E); }; bool AssignExprCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (!FD->isThisDeclarationADefinition() || ConsumerInstance->isInIncludedFile(FD)) return true; ConsumerInstance->StmtVisitor->setCurrentFunctionDecl(FD); ConsumerInstance->StmtVisitor->TraverseDecl(FD); ConsumerInstance->StmtVisitor->setCurrentFunctionDecl(NULL); return true; } // It is used to handle the case where if-then or else branch // is not treated as a CompoundStmt. So it cannot be traversed // from VisitCompoundStmt, e.g., // if (x) // foo(bar()) bool AssignExprStatementVisitor::VisitIfStmt(IfStmt *IS) { Expr *E = IS->getCond(); handleSubExpr(E); Stmt *ThenB = IS->getThen(); visitNonCompoundStmt(ThenB); Stmt *ElseB = IS->getElse(); visitNonCompoundStmt(ElseB); return false; } // It causes unsound transformation because // the semantics of loop execution has been changed. // For example, // int foo(int x) // { // int i; // for(i = 0; i < bar(bar(x)); i++) // ... // } // will be transformed to: // int foo(int x) // { // int i; // int tmp_var = bar(x); // for(i = 0; i < bar(tmp_var); i++) // ... // } bool AssignExprStatementVisitor::VisitForStmt(ForStmt *FS) { Stmt *Init = FS->getInit(); Expr *InitE = NULL; if (Init) InitE = dyn_cast(Init); if (InitE) handleSubExpr(InitE); else TraverseStmt(Init); Expr *Cond = FS->getCond(); handleSubExpr(Cond); Expr *Inc = FS->getInc(); handleSubExpr(Inc); Stmt *Body = FS->getBody(); visitNonCompoundStmt(Body); return false; } bool AssignExprStatementVisitor::VisitWhileStmt(WhileStmt *WS) { Expr *E = WS->getCond(); handleSubExpr(E); Stmt *Body = WS->getBody(); visitNonCompoundStmt(Body); return false; } bool AssignExprStatementVisitor::VisitDoStmt(DoStmt *DS) { Expr *E = DS->getCond(); handleSubExpr(E); Stmt *Body = DS->getBody(); visitNonCompoundStmt(Body); return false; } bool AssignExprStatementVisitor::VisitCallExpr(CallExpr *CallE) { for (CallExpr::arg_iterator I = CallE->arg_begin(), E = CallE->arg_end(); I != E; ++I) { Expr *Exp = *I; handleSubExpr(Exp); } return false; } void AssignExprStatementVisitor::handleSubExpr(Expr *E) { if (!E) return; if (dyn_cast(CurrentStmt)) return; BinaryOperator *BinOp = dyn_cast(E->IgnoreParenCasts()); if (!BinOp) { TraverseStmt(E); return; } if (!BinOp->isAssignmentOp() && !BinOp->isCompoundAssignmentOp()) { TraverseStmt(E); return; } TransAssert(std::find(ConsumerInstance->ValidAssignExprs.begin(), ConsumerInstance->ValidAssignExprs.end(), BinOp) == ConsumerInstance->ValidAssignExprs.end()); ConsumerInstance->ValidAssignExprs.push_back(BinOp); ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum != ConsumerInstance->TransformationCounter) return; ConsumerInstance->TheFuncDecl = CurrentFuncDecl; ConsumerInstance->TheStmt = CurrentStmt; ConsumerInstance->TheAssignExpr = BinOp; ConsumerInstance->NeedParen = NeedParen; } void LiftAssignmentExpr::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new AssignExprCollectionVisitor(this); StmtVisitor = new AssignExprStatementVisitor(this); } bool LiftAssignmentExpr::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void LiftAssignmentExpr::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransAssert(TheStmt && "NULL TheStmt!"); TransAssert(TheAssignExpr && "NULL TheAssignExpr"); TransAssert(TheAssignExpr->isAssignmentOp() || TheAssignExpr->isCompoundAssignmentOp()); addNewAssignStmt(); replaceAssignExpr(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool LiftAssignmentExpr::addNewAssignStmt(void) { std::string AssignStr(""); RewriteHelper->getExprString(TheAssignExpr, AssignStr); AssignStr += ";"; return RewriteHelper->addStringBeforeStmt(TheStmt, AssignStr, NeedParen); } bool LiftAssignmentExpr::replaceAssignExpr(void) { const Expr *Lhs = TheAssignExpr->getLHS(); std::string LhsStr(""); RewriteHelper->getExprString(Lhs, LhsStr); return RewriteHelper->replaceExpr(TheAssignExpr, LhsStr); } LiftAssignmentExpr::~LiftAssignmentExpr(void) { delete CollectionVisitor; delete StmtVisitor; } cvise-2.3.0/clang_delta/LiftAssignmentExpr.h000066400000000000000000000034441402162750500210300ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef LIFT_ASSIGNMENT_EXPR_H #define LIFT_ASSIGNMENT_EXPR_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class Stmt; class BinaryOperator; } class AssignExprCollectionVisitor; class AssignExprStatementVisitor; class LiftAssignmentExpr : public Transformation { friend class AssignExprCollectionVisitor; friend class AssignExprStatementVisitor; public: LiftAssignmentExpr(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), StmtVisitor(NULL), TheFuncDecl(NULL), TheStmt(NULL), TheAssignExpr(NULL), NeedParen(false) { } ~LiftAssignmentExpr(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool addNewAssignStmt(void); bool replaceAssignExpr(void); clang::SmallVector ValidAssignExprs; AssignExprCollectionVisitor *CollectionVisitor; AssignExprStatementVisitor *StmtVisitor; clang::FunctionDecl *TheFuncDecl; clang::Stmt *TheStmt; clang::BinaryOperator *TheAssignExpr; bool NeedParen; // Unimplemented LiftAssignmentExpr(void); LiftAssignmentExpr(const LiftAssignmentExpr &); void operator=(const LiftAssignmentExpr &); }; #endif cvise-2.3.0/clang_delta/LocalToGlobal.cpp000066400000000000000000000174171402162750500202600ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "LocalToGlobal.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Move the declaraion of a non-static local variable from \ a function to the global scope. Also rename the moved local variable \ to avoid possible name conflicts. \n"; static RegisterTransformation Trans("local-to-global", DescriptionMsg); class LocalToGlobalCollectionVisitor : public RecursiveASTVisitor { public: explicit LocalToGlobalCollectionVisitor(LocalToGlobal *Instance) : ConsumerInstance(Instance), CurrentFuncDecl(NULL) { } bool VisitVarDecl(VarDecl *VD); bool VisitCXXCatchStmt(CXXCatchStmt *DS); void setCurrentFuncDecl(FunctionDecl *FD) { CurrentFuncDecl = FD; } private: LocalToGlobal *ConsumerInstance; FunctionDecl *CurrentFuncDecl; }; class LocalToGlobalFunctionVisitor : public RecursiveASTVisitor { public: explicit LocalToGlobalFunctionVisitor(LocalToGlobal *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *VD); private: LocalToGlobal *ConsumerInstance; }; class LToGASTVisitor : public RecursiveASTVisitor { public: typedef RecursiveASTVisitor Inherited; explicit LToGASTVisitor(LocalToGlobal *Instance) : ConsumerInstance(Instance) { } bool VisitDeclStmt(DeclStmt *DS); bool VisitDeclRefExpr(DeclRefExpr *VarRefExpr); private: LocalToGlobal *ConsumerInstance; bool makeLocalAsGlobalVar(FunctionDecl *FD, VarDecl *VD, Decl *PrevDecl, bool StmtRemoved); }; bool LocalToGlobalFunctionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (FD->isThisDeclarationADefinition()) { ConsumerInstance->LocalVarCollectionVisitor->setCurrentFuncDecl(FD); ConsumerInstance->LocalVarCollectionVisitor->TraverseDecl(FD); ConsumerInstance->LocalVarCollectionVisitor->setCurrentFuncDecl(NULL); } return true; } bool LocalToGlobalCollectionVisitor::VisitVarDecl(VarDecl *VD) { TransAssert(CurrentFuncDecl && "NULL CurrentFuncDecl!"); if (ConsumerInstance->isInIncludedFile(VD) || !VD->isLocalVarDecl() || VD->isStaticLocal() || VD->hasExternalStorage() || ConsumerInstance->SkippedVars.count(VD->getCanonicalDecl())) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheVarDecl = VD; ConsumerInstance->TheFuncDecl = CurrentFuncDecl; ConsumerInstance->setNewName(CurrentFuncDecl, VD); } return true; } bool LocalToGlobalCollectionVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) { const VarDecl *VD = S->getExceptionDecl(); if (VD) { ConsumerInstance->SkippedVars.insert(VD->getCanonicalDecl()); } return true; } void LocalToGlobal::Initialize(ASTContext &context) { Transformation::Initialize(context); LocalVarCollectionVisitor = new LocalToGlobalCollectionVisitor(this); FunctionVisitor = new LocalToGlobalFunctionVisitor(this); TransformationASTVisitor = new LToGASTVisitor(this); } void LocalToGlobal::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { FunctionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TransformationASTVisitor && "NULL TransformationASTVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransAssert(TheVarDecl && "NULL TheVarDecl!"); TransformationASTVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void LocalToGlobal::setNewName(FunctionDecl *FD, const VarDecl *VD) { std::string NewName; NewName = FD->getNameInfo().getAsString(); NewName += "_"; NewName += VD->getNameAsString(); // also backup the new name TheNewDeclName = NewName; } LocalToGlobal::~LocalToGlobal(void) { delete FunctionVisitor; delete LocalVarCollectionVisitor; delete TransformationASTVisitor; } bool LToGASTVisitor::makeLocalAsGlobalVar(FunctionDecl *FD, VarDecl *VD, Decl *PrevDecl, bool StmtRemoved) { std::string GlobalVarStr; std::string NewName = ConsumerInstance->getNewName(); auto& TheRewriter = ConsumerInstance->TheRewriter; if (StmtRemoved) { SourceRange Range = PrevDecl->getSourceRange(); ConsumerInstance->RewriteHelper->getStringBetweenLocs( GlobalVarStr, Range.getBegin(), VD->getLocation()); GlobalVarStr += NewName; } else { QualType T = VD->getType(); T.getAsStringInternal(NewName, ConsumerInstance->Context->getPrintingPolicy()); GlobalVarStr = NewName; if (VD->hasInit()) { const Expr *InitExpr = VD->getInit(); std::string InitStr(""); ConsumerInstance->RewriteHelper->getExprString(InitExpr, InitStr); GlobalVarStr += " = "; GlobalVarStr += InitStr; } } GlobalVarStr += ";\n"; for (DeclContext* DC = FD; DC; DC = DC->getParent()) { if (DC->getParent() && DC->getParent()->isTranslationUnit()) { TheRewriter.InsertTextBefore(cast(DC)->getBeginLoc(), GlobalVarStr); return true; } } return ConsumerInstance->RewriteHelper-> insertStringBeforeFunc(FD, GlobalVarStr); } bool LToGASTVisitor::VisitDeclStmt(DeclStmt *DS) { Decl *PrevDecl = NULL; VarDecl *VD = NULL; int NumDecls = 0; int VarPos = 0; for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { NumDecls++; // we have got the var if (VD) continue; Decl *CurrDecl = (*I); if (CurrDecl != ConsumerInstance->TheVarDecl) { PrevDecl = (*I); continue; } TransAssert(!VD && "Duplicated Definition?"); VD = dyn_cast(CurrDecl); TransAssert(VD && "Bad VarDecl!"); VarPos = NumDecls - 1; } if (!VD) return true; bool IsFirstDecl = (!VarPos); bool StmtRemoved = false; ConsumerInstance->RewriteHelper->removeVarFromDeclStmt (DS, VD, PrevDecl, IsFirstDecl, &StmtRemoved); return makeLocalAsGlobalVar(ConsumerInstance->TheFuncDecl, VD, PrevDecl, StmtRemoved); } bool LToGASTVisitor::VisitDeclRefExpr(DeclRefExpr *VarRefExpr) { if (!ConsumerInstance->TheVarDecl) return true; const ValueDecl *OrigDecl = VarRefExpr->getDecl(); if (OrigDecl != ConsumerInstance->TheVarDecl) return true; SourceRange ExprRange = VarRefExpr->getSourceRange(); SourceLocation StartLoc = ExprRange.getBegin(); SourceLocation EndLoc = ExprRange.getEnd(); if (StartLoc.isMacroID()) { StartLoc = ConsumerInstance->SrcManager->getSpellingLoc(StartLoc); EndLoc = ConsumerInstance->SrcManager->getSpellingLoc(EndLoc); } return !(ConsumerInstance->TheRewriter.ReplaceText( SourceRange(StartLoc, EndLoc), ConsumerInstance->TheNewDeclName)); } cvise-2.3.0/clang_delta/LocalToGlobal.h000066400000000000000000000036131402162750500177160ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef LOCAL_TO_GLOBAL_H #define LOCAL_TO_GLOBAL_H #include #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class ReturnStmt; class ParmVarDecl; } class LocalToGlobalFunctionVisitor; class LToGASTVisitor; class LocalToGlobalCollectionVisitor; class LocalToGlobal : public Transformation { friend class LocalToGlobalFunctionVisitor; friend class LToGASTVisitor; friend class LocalToGlobalCollectionVisitor; public: LocalToGlobal(const char *TransName, const char *Desc) : Transformation(TransName, Desc), FunctionVisitor(NULL), LocalVarCollectionVisitor(NULL), TransformationASTVisitor(NULL), TheFuncDecl(NULL), TheVarDecl(NULL), TheNewDeclName("") { } ~LocalToGlobal(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void setNewName(clang::FunctionDecl *FD, const clang::VarDecl *VD); std::string getNewName(void) { return TheNewDeclName; } llvm::SmallPtrSet SkippedVars; LocalToGlobalFunctionVisitor *FunctionVisitor; LocalToGlobalCollectionVisitor *LocalVarCollectionVisitor; LToGASTVisitor *TransformationASTVisitor; clang::FunctionDecl *TheFuncDecl; const clang::VarDecl *TheVarDecl; std::string TheNewDeclName; // Unimplemented LocalToGlobal(void); LocalToGlobal(const LocalToGlobal &); void operator=(const LocalToGlobal &); }; #endif cvise-2.3.0/clang_delta/MoveFunctionBody.cpp000066400000000000000000000065321402162750500210300ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "MoveFunctionBody.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Move function body towards its declaration. \ Note that this pass would generate incompilable code. \n"; static RegisterTransformation Trans("move-function-body", DescriptionMsg); void MoveFunctionBody::Initialize(ASTContext &context) { Transformation::Initialize(context); } bool MoveFunctionBody::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { FunctionDecl *FD = dyn_cast(*I); if (!FD || isInIncludedFile(FD)) { PrevFunctionDecl = NULL; continue; } FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (FD->isThisDeclarationADefinition()) { FunctionDecl *FDDecl = AllValidFunctionDecls[CanonicalFD]; if (!FDDecl) { PrevFunctionDecl = NULL; continue; } // Declaration and Definition are next to each other if (PrevFunctionDecl) { FunctionDecl *CanonicalPrevFD = PrevFunctionDecl->getCanonicalDecl(); if (CanonicalFD == CanonicalPrevFD) { PrevFunctionDecl = NULL; continue; } } FuncDeclToFuncDef[FDDecl] = FD; } PrevFunctionDecl = FD; // We only need the first FunctionDecl if (AllValidFunctionDecls[CanonicalFD]) continue; AllValidFunctionDecls[CanonicalFD] = FD; } return true; } void MoveFunctionBody::HandleTranslationUnit(ASTContext &Ctx) { doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFunctionDecl && "NULL TheFunctionDecl!"); TransAssert(!TheFunctionDecl->isThisDeclarationADefinition() && "Invalid Function Declaration!"); TransAssert(TheFunctionDef && "NULL TheFunctionDef!"); TransAssert(TheFunctionDef->isThisDeclarationADefinition() && "Invalid Function Definition!"); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void MoveFunctionBody::doAnalysis(void) { for (FuncDeclToFuncDeclMap::iterator I = FuncDeclToFuncDef.begin(), E = FuncDeclToFuncDef.end(); I != E; ++I) { ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheFunctionDecl = (*I).first; TheFunctionDef = (*I).second; } } } void MoveFunctionBody::doRewriting(void) { std::string FuncDefStr; RewriteHelper->getFunctionDefStrAndRemove(TheFunctionDef, FuncDefStr); RewriteHelper->addStringAfterFuncDecl(TheFunctionDecl, FuncDefStr); } MoveFunctionBody::~MoveFunctionBody(void) { // Nothing to do } cvise-2.3.0/clang_delta/MoveFunctionBody.h000066400000000000000000000030461402162750500204720ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef MOVE_FUNCTION_BODY_H #define MOVE_FUNCTION_BODY_H #include #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; } class MoveFunctionBody : public Transformation { public: MoveFunctionBody(const char *TransName, const char *Desc) : Transformation(TransName, Desc), TheFunctionDecl(NULL), TheFunctionDef(NULL), PrevFunctionDecl(NULL) { } ~MoveFunctionBody(void); private: typedef llvm::DenseMap FuncDeclToFuncDeclMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doAnalysis(void); void doRewriting(void); FuncDeclToFuncDeclMap AllValidFunctionDecls; FuncDeclToFuncDeclMap FuncDeclToFuncDef; clang::FunctionDecl *TheFunctionDecl; clang::FunctionDecl *TheFunctionDef; clang::FunctionDecl *PrevFunctionDecl; // Unimplemented MoveFunctionBody(void); MoveFunctionBody(const MoveFunctionBody &); void operator=(const MoveFunctionBody &); }; #endif cvise-2.3.0/clang_delta/MoveGlobalVar.cpp000066400000000000000000000075421402162750500203000ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2015, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "MoveGlobalVar.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Try to move global var/struct/union declarations above all function \ declarations except printf. Also move the declaration of printf to the top of \ the reduce code if it exists and is not at the top of the code.\n"; static RegisterTransformation Trans("move-global-var", DescriptionMsg); void MoveGlobalVar::Initialize(ASTContext &context) { Transformation::Initialize(context); } bool MoveGlobalVar::isSpecialDecl(const std::string &Name) { return ((Name == "__va_list_tag") || (Name == "__builtin_va_list")); } bool MoveGlobalVar::HandleTopLevelDecl(DeclGroupRef D) { if (TransformationManager::isCXXLangOpt()) { ValidInstanceNum = 0; return true; } DeclGroupRef::iterator I = D.begin(); TransAssert((I != D.end()) && "Bad DeclGroupRef!"); if (isInIncludedFile(*I)) return true; const NamedDecl *ND = dyn_cast(*I); if (!TheFirstDecl && ND && isSpecialDecl(ND->getNameAsString())) return true; FunctionDecl *FD = dyn_cast(*I); if (FD) { handleFunctionDecl(FD); } else { handleOtherDecl(D); } if (!TheFirstDecl) TheFirstDecl = (*I); return true; } void MoveGlobalVar::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); if (ThePrintfDecl) liftPrintfDecl(); else liftOtherDecl(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void MoveGlobalVar::handleFunctionDecl(const FunctionDecl *FD) { if (FD->getNameAsString() == "printf") { if (ThePrintfDecl || !TheFirstDecl || FD->isThisDeclarationADefinition()) return; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) ThePrintfDecl = FD; } else if (!TheFirstFunctionDecl) { TheFirstFunctionDecl = FD; } } void MoveGlobalVar::handleOtherDecl(DeclGroupRef DGR) { if (!TheFirstFunctionDecl) return; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) TheDGRPointer = DGR.getAsOpaquePtr(); } void MoveGlobalVar::liftPrintfDecl(void) { TransAssert(ThePrintfDecl && TheFirstDecl && (ThePrintfDecl != TheFirstDecl) && "Invalid printf decl!"); std::string PrintfDeclStr; RewriteHelper->getFunctionDeclStrAndRemove(ThePrintfDecl, PrintfDeclStr); SourceRange DeclRange = TheFirstDecl->getSourceRange(); SourceLocation StartLoc = DeclRange.getBegin(); PrintfDeclStr += ";\n"; TheRewriter.InsertTextBefore(StartLoc, PrintfDeclStr); } void MoveGlobalVar::liftOtherDecl(void) { TransAssert(TheDGRPointer && "NULL DGR pointer!"); TransAssert(TheFirstFunctionDecl && "NULL First Decl!"); DeclGroupRef DGR = DeclGroupRef::getFromOpaquePtr(TheDGRPointer); std::string DGRStr; RewriteHelper->getEntireDeclGroupStrAndRemove(DGR, DGRStr); SourceRange DeclRange = TheFirstFunctionDecl->getSourceRange(); SourceLocation StartLoc = DeclRange.getBegin(); DGRStr += ";\n"; TheRewriter.InsertTextBefore(StartLoc, DGRStr); } MoveGlobalVar::~MoveGlobalVar(void) { // Nothing to do } cvise-2.3.0/clang_delta/MoveGlobalVar.h000066400000000000000000000031241402162750500177350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef MOVE_GLOBAL_VAR_H #define MOVE_GLOBAL_VAR_H #include #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; } class MoveGlobalVar : public Transformation { public: MoveGlobalVar(const char *TransName, const char *Desc) : Transformation(TransName, Desc), TheFirstFunctionDecl(NULL), ThePrintfDecl(NULL), TheFirstDecl(NULL), TheDGRPointer(NULL) { } ~MoveGlobalVar(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isSpecialDecl(const std::string &Name); void handleFunctionDecl(const clang::FunctionDecl *FD); void handleOtherDecl(clang::DeclGroupRef DGR); void liftPrintfDecl(void); void liftOtherDecl(void); // The first FunctionDecl which is not printf const clang::FunctionDecl *TheFirstFunctionDecl; const clang::FunctionDecl *ThePrintfDecl; const clang::Decl *TheFirstDecl; void *TheDGRPointer; // Unimplemented MoveGlobalVar(void); MoveGlobalVar(const MoveGlobalVar &); void operator=(const MoveGlobalVar &); }; #endif cvise-2.3.0/clang_delta/ParamToGlobal.cpp000066400000000000000000000132421402162750500202560ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ParamToGlobal.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Lift the declaraion of a parameter from a function \ to the global scope. Also rename the lifted parameter \ to avoid possible name conflicts. Note that for C++ code, \ this pass actually lifts a parameter from a member function \ to the class scope rather than the global scope. \n"; static RegisterTransformation Trans("param-to-global", DescriptionMsg); class ParamToGlobalASTVisitor : public RecursiveASTVisitor { public: explicit ParamToGlobalASTVisitor(ParamToGlobal *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ParamToGlobal *ConsumerInstance; }; class ParamToGlobalRewriteVisitor : public CommonParameterRewriteVisitor { public: explicit ParamToGlobalRewriteVisitor(ParamToGlobal *Instance) : CommonParameterRewriteVisitor(Instance) { } bool VisitDeclRefExpr(DeclRefExpr *ParmRefExpr); }; bool ParamToGlobalASTVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isValidFuncDecl(FD->getCanonicalDecl())) { ConsumerInstance->ValidFuncDecls.push_back(FD->getCanonicalDecl()); } return true; } std::string ParamToGlobal::getNewName(FunctionDecl *FP, const ParmVarDecl *PV) { std::string NewName; NewName = FP->getNameInfo().getAsString(); NewName += "_"; NewName += PV->getNameAsString(); // also backup the new name TheNewDeclName = NewName; return NewName; } bool ParamToGlobalRewriteVisitor::VisitDeclRefExpr(DeclRefExpr *ParmRefExpr) { const ValueDecl *OrigDecl = ParmRefExpr->getDecl(); if (!ConsumerInstance->TheParmVarDecl) return true; if (OrigDecl != ConsumerInstance->TheParmVarDecl) return true; SourceRange ExprRange = ParmRefExpr->getSourceRange(); return !(ConsumerInstance->TheRewriter.ReplaceText(ExprRange, ConsumerInstance->TheNewDeclName)); } void ParamToGlobal::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ParamToGlobalASTVisitor(this); RewriteVisitor = new ParamToGlobalRewriteVisitor(this); } void ParamToGlobal::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransAssert((TheParamPos >= 0) && "Invalid parameter position!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); RewriteVisitor->rewriteAllExprs(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool ParamToGlobal::transformParamVar(FunctionDecl *FD, const ParmVarDecl *PV) { std::string PName = PV->getNameAsString(); // Safe to omit an un-named parameter if (PName.empty()) return true; std::string GlobalVarStr; GlobalVarStr = PV->getType().getAsString(); GlobalVarStr += " "; GlobalVarStr += getNewName(FD, PV); GlobalVarStr += ";\n"; return RewriteHelper->insertStringBeforeFunc(FD, GlobalVarStr); } bool ParamToGlobal::rewriteFuncDecl(clang::FunctionDecl *FD) { const clang::ParmVarDecl *PV = FD->getParamDecl(TheParamPos); TransAssert(PV && "Unmatched ParamPos!"); RewriteHelper->removeParamFromFuncDecl(PV, FD->getNumParams(), TheParamPos); if (FD->isThisDeclarationADefinition()) { TheParmVarDecl = PV; if (!transformParamVar(FD, PV)) return false; } return true; } bool ParamToGlobal::isValidFuncDecl(FunctionDecl *FD) { bool IsValid = false; int ParamPos = 0; TransAssert(isa(FD) && "Must be a FunctionDecl"); if (isInIncludedFile(FD)) return false; // Skip the case like foo(int, ...), because we cannot remove // the "int" there if (FD->isVariadic() && (FD->getNumParams() == 1)) { return false; } if (FD->isOverloadedOperator()) return false; // Avoid duplications if (std::find(ValidFuncDecls.begin(), ValidFuncDecls.end(), FD) != ValidFuncDecls.end()) return false; for (FunctionDecl::param_const_iterator PI = FD->param_begin(), PE = FD->param_end(); PI != PE; ++PI) { if ((*PI)->isImplicit() || (*PI)->getSourceRange().isInvalid()) continue; if (!FD->hasBody() && (*PI)->getNameAsString().empty()) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheFuncDecl = FD; TheParamPos = ParamPos; } IsValid = true; ParamPos++; } return IsValid; } ParamToGlobal::~ParamToGlobal(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ParamToGlobal.h000066400000000000000000000043001402162750500177160ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef PARAM_TO_GLOBAL_H #define PARAM_TO_GLOBAL_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" #include "CommonParameterRewriteVisitor.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class ReturnStmt; class ParmVarDecl; } class ParamToGlobalASTVisitor; class ParamToGlobalRewriteVisitor; template class CommonParameterRewriteVisitor; class ParamToGlobal : public Transformation { friend class ParamToGlobalASTVisitor; friend class ParamToGlobalRewriteVisitor; friend class CommonParameterRewriteVisitor; public: ParamToGlobal(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheFuncDecl(NULL), TheParmVarDecl(NULL), TheNewDeclName(""), TheParamPos(-1) { } ~ParamToGlobal(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool transformParamVar(clang::FunctionDecl *FD, const clang::ParmVarDecl *PV); bool rewriteFuncDecl(clang::FunctionDecl *FD); std::string getNewName(clang::FunctionDecl *FP, const clang::ParmVarDecl *PV); bool isValidFuncDecl(clang::FunctionDecl *FD); llvm::SmallVector ValidFuncDecls; ParamToGlobalASTVisitor *CollectionVisitor; ParamToGlobalRewriteVisitor *RewriteVisitor; clang::FunctionDecl *TheFuncDecl; const clang::ParmVarDecl *TheParmVarDecl; std::string TheNewDeclName; int TheParamPos; // Unimplemented ParamToGlobal(void); ParamToGlobal(const ParamToGlobal &); void operator=(const ParamToGlobal &); }; #endif cvise-2.3.0/clang_delta/ParamToLocal.cpp000066400000000000000000000131551402162750500201130ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ParamToLocal.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove an integaral/enumeration parameter from the declaration \ of a function. Define the removed parameter as a local variable \ of the same function. Initialze the newly local variable to be \ 0. Also, make corresponding changes on all of the call sites of \ the modified function.\n"; static RegisterTransformation Trans("param-to-local", DescriptionMsg); class ParamToLocalASTVisitor : public RecursiveASTVisitor { public: explicit ParamToLocalASTVisitor(ParamToLocal *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ParamToLocal *ConsumerInstance; }; class ParamToLocalRewriteVisitor : public CommonParameterRewriteVisitor { public: explicit ParamToLocalRewriteVisitor(ParamToLocal *Instance) : CommonParameterRewriteVisitor(Instance) { } }; bool ParamToLocalASTVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isValidFuncDecl(FD->getCanonicalDecl())) { ConsumerInstance->ValidFuncDecls.push_back(FD->getCanonicalDecl()); } return true; } void ParamToLocal::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ParamToLocalASTVisitor(this); RewriteVisitor = new ParamToLocalRewriteVisitor(this); } void ParamToLocal::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransAssert((TheParamPos >= 0) && "Invalid parameter position!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); RewriteVisitor->rewriteAllExprs(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } // For CXX, this function could generate bad code, e.g., // class A { // void foo(void) {...} // void foo(int x) {...} // }; // // will be transformed to // class A { // void foo(void) {...} // void foo(void) {int x ...} // }; bool ParamToLocal::rewriteFuncDecl(FunctionDecl *FD) { const ParmVarDecl *PV = FD->getParamDecl(TheParamPos); TransAssert(PV && "Unmatched ParamPos!"); RewriteHelper->removeParamFromFuncDecl(PV, FD->getNumParams(), TheParamPos); if (FD->isThisDeclarationADefinition()) { if (!transformParamVar(FD, PV)) return false; } return true; } // ISSUE: we could have another type of bad transformation, e.g., // class A { ... }; // class B : public A { // B(int x) : A(x) {...} // }; // ==> // class A { ... }; // class B : public A { // B(void) : A(x) {int x ...} // }; // hence x is undeclared for A(x) bool ParamToLocal::transformParamVar(FunctionDecl *FD, const ParmVarDecl *PV) { std::string PName = PV->getNameAsString(); // Safe to omit an un-named parameter if (PName.empty()) return true; std::string LocalVarStr; LocalVarStr += PV->getType().getAsString(); LocalVarStr += " "; LocalVarStr += PV->getNameAsString(); QualType PVType = PV->getOriginalType(); const Type *T = PVType.getTypePtr(); if ( const Expr *DefaultArgE = PV->getDefaultArg() ) { std::string ArgStr; RewriteHelper->getExprString(DefaultArgE, ArgStr); LocalVarStr += " = "; LocalVarStr += ArgStr; } else if (T->isPointerType() || T->isIntegralType(*Context)) { LocalVarStr += " = 0"; } LocalVarStr += ";"; return RewriteHelper->addLocalVarToFunc(LocalVarStr, FD); } bool ParamToLocal::isValidFuncDecl(FunctionDecl *FD) { bool IsValid = false; int ParamPos = 0; TransAssert(isa(FD) && "Must be a FunctionDecl"); if (isInIncludedFile(FD)) return false; // Skip the case like foo(int, ...), because we cannot remove // the "int" there if (FD->isVariadic() && (FD->getNumParams() == 1)) { return false; } if (FD->isOverloadedOperator()) return false; // Avoid duplications if (std::find(ValidFuncDecls.begin(), ValidFuncDecls.end(), FD) != ValidFuncDecls.end()) return false; for (FunctionDecl::param_const_iterator PI = FD->param_begin(), PE = FD->param_end(); PI != PE; ++PI) { if ((*PI)->isImplicit() || (*PI)->getSourceRange().isInvalid()) continue; if (!FD->hasBody() && (*PI)->getNameAsString().empty()) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheFuncDecl = FD; TheParamPos = ParamPos; } IsValid = true; ParamPos++; } return IsValid; } ParamToLocal::~ParamToLocal(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ParamToLocal.h000066400000000000000000000036171402162750500175620ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef PARAM_TO_LOCAL_H #define PARAM_TO_LOCAL_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" #include "CommonParameterRewriteVisitor.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class ParmVarDecl; } class ParamToLocalASTVisitor; class ParamToLocalRewriteVisitor; template class CommonParameterRewriteVisitor; class ParamToLocal : public Transformation { friend class ParamToLocalASTVisitor; friend class ParamToLocalRewriteVisitor; friend class CommonParameterRewriteVisitor; public: ParamToLocal(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheFuncDecl(NULL), TheParamPos(-1) { } ~ParamToLocal(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isValidFuncDecl(clang::FunctionDecl *FD); bool transformParamVar(clang::FunctionDecl *FD, const clang::ParmVarDecl *PV); bool rewriteFuncDecl(clang::FunctionDecl *FD); llvm::SmallVector ValidFuncDecls; ParamToLocalASTVisitor *CollectionVisitor; ParamToLocalRewriteVisitor *RewriteVisitor; clang::FunctionDecl *TheFuncDecl; int TheParamPos; // Unimplemented ParamToLocal(void); ParamToLocal(const ParamToLocal &); void operator=(const ParamToLocal &); }; #endif cvise-2.3.0/clang_delta/README.txt000066400000000000000000000020031402162750500165550ustar00rootroot00000000000000-------------------------------------------------------------------- Normally clang_delta is invoked from C-Vise. But if you wish to invoke it manually: ./clang_delta --transformation=xx --counter=xx foo.c For detailed options: ./clang_delta --help -------------------------------------------------------------------- Testing clang_delta: * clang_delta/tests is the place for adding unittests for clang_delta To run the tests, please follow the steps below: If you use make: $ cd /cvise/top/dir $ ./configure $ make $ cd clang_delta $ make check-clang-delta If you use cmake: $ /cvise/top/dir $ mkdir build $ cd build $ cmake .. $ make $ make check-clang-delta * test_transformation `test_transformation' is designed to test clang_delta `test_transformation -help' gives detailed information. -------------------------------------------------------------------- Known bugs: * bad transformation on functions involved with function pointers -------------------------------------------------------------------- cvise-2.3.0/clang_delta/ReduceArrayDim.cpp000066400000000000000000000247321402162750500204400ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2018, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReduceArrayDim.h" #include #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Reduce the dimension of an array. Each transformation iteration \ reduces one dimension in the following way: \n\ int a[2][3][4]; \n\ void foo(void) {... a[1][2][3] ... }\n\ ===> \n\ int a[2][3 * 4]; \n\ void foo(void) {... a[1][3 * 2 + 3] ... }\n\ The binary operations will be computed to constant during the \ transformation if possible. Array fields are not handled right now. \ Also, this pass only works with ConstantArrayType and IncompleteArrayType.\n"; static RegisterTransformation Trans("reduce-array-dim", DescriptionMsg); class ReduceArrayDimCollectionVisitor : public RecursiveASTVisitor { public: explicit ReduceArrayDimCollectionVisitor(ReduceArrayDim *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); private: ReduceArrayDim *ConsumerInstance; }; bool ReduceArrayDimCollectionVisitor::VisitVarDecl(VarDecl *VD) { ConsumerInstance->addOneVar(VD); return true; } class ReduceArrayDimRewriteVisitor : public RecursiveASTVisitor { public: explicit ReduceArrayDimRewriteVisitor(ReduceArrayDim *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitArraySubscriptExpr(ArraySubscriptExpr *DRE); private: ReduceArrayDim *ConsumerInstance; }; bool ReduceArrayDimRewriteVisitor::VisitVarDecl(VarDecl *VD) { const VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (CanonicalVD != ConsumerInstance->TheVarDecl) return true; ConsumerInstance->rewriteOneVarDecl(VD); return true; } bool ReduceArrayDimRewriteVisitor::VisitArraySubscriptExpr( ArraySubscriptExpr *ASE) { ConsumerInstance->handleOneArraySubscriptExpr(ASE); return true; } void ReduceArrayDim::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReduceArrayDimCollectionVisitor(this); RewriteVisitor = new ReduceArrayDimRewriteVisitor(this); } bool ReduceArrayDim::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void ReduceArrayDim::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheVarDecl && "NULL TheVarDecl!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (!Rewritten) { TransError = TransNoTextModificationError; return; } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReduceArrayDim::addOneVar(const VarDecl *VD) { if (isInIncludedFile(VD)) return; const Type *Ty = VD->getType().getTypePtr(); const ArrayType *ArrayTy = dyn_cast(Ty); if (!ArrayTy) return; unsigned int ArrayDim = getArrayDimension(ArrayTy); if (ArrayDim <= 1) return; // Skip these two array types if (dyn_cast(ArrayTy) || dyn_cast(ArrayTy)) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (VisitedVarDecls.count(CanonicalVD)) return; VisitedVarDecls.insert(CanonicalVD); ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) { TheVarDecl = CanonicalVD; } } // This function doesn't consider nested brackets, which won't // exist for the definitions of ConstantArrayType and IncompleteArrayType void ReduceArrayDim::getBracketLocPairs(const VarDecl *VD, unsigned int Dim, BracketLocPairVector &BPVec) { SourceLocation StartLoc = VD->getLocation(); SourceLocation BPStartLoc, BPEndLoc; for (unsigned int I = 0; I < Dim; ++I) { BPStartLoc = RewriteHelper->getLocationUntil(StartLoc, '['); BPEndLoc = RewriteHelper->getLocationUntil(BPStartLoc, ']'); BracketLocPair *LocPair = new BracketLocPair(); LocPair->first = BPStartLoc; LocPair->second = BPEndLoc; BPVec.push_back(LocPair); StartLoc = BPEndLoc; } } void ReduceArrayDim::freeBracketLocPairs(BracketLocPairVector &BPVec) { for (BracketLocPairVector::iterator I = BPVec.begin(), E = BPVec.end(); I != E; ++I) { delete (*I); } } void ReduceArrayDim::getInitListExprs(InitListExprVector &InitVec, const InitListExpr *ILE, unsigned int Dim) { unsigned int NumInits = ILE->getNumInits(); for (unsigned int I = 0; I < NumInits; ++I) { const Expr *E = ILE->getInit(I); const InitListExpr *SubILE = dyn_cast(E); if (!SubILE) continue; if (Dim == 1) { InitVec.push_back(SubILE); } else { getInitListExprs(InitVec, SubILE, Dim-1); } } } void ReduceArrayDim::rewriteInitListExpr(const InitListExpr *ILE, unsigned int Dim) { TransAssert((Dim > 1) && "Invalid array dimension!"); InitListExprVector InitVec; getInitListExprs(InitVec, ILE, Dim-1); for (InitListExprVector::reverse_iterator I = InitVec.rbegin(), E = InitVec.rend(); I != E; ++I) { SourceLocation RBLoc = (*I)->getRBraceLoc(); SourceLocation RLLoc = (*I)->getLBraceLoc(); const char *RBBuf = SrcManager->getCharacterData(RBLoc); const char *RLBuf = SrcManager->getCharacterData(RLLoc); // make sure RBBuf and RLBuf are correct. They could be incorrect // for cases like: int a[2][2] = {1} if (((*RBBuf) == '}') && ((*RLBuf) == '{')) { TheRewriter.RemoveText(RBLoc, 1); TheRewriter.RemoveText(RLLoc, 1); } } } unsigned ReduceArrayDim::getArraySize(const ArrayType *ATy) { if (const ConstantArrayType *CstArrayTy = dyn_cast(ATy)) { return getConstArraySize(CstArrayTy); } return 1; } void ReduceArrayDim::rewriteOneVarDecl(const VarDecl *VD) { const Type *Ty = VD->getType().getTypePtr(); const ArrayType *ArrayTy = dyn_cast(Ty); TransAssert(ArrayTy && "Invalid ArrayType!"); ArraySubTypeVector TyVec; unsigned int Dim = getArrayDimensionAndTypes(ArrayTy, TyVec); if (VD->hasInit()) { const Expr *InitE = VD->getInit(); const InitListExpr *ILE = dyn_cast(InitE); if (ILE) rewriteInitListExpr(ILE, Dim); } BracketLocPairVector BPVector; getBracketLocPairs(VD, Dim, BPVector); TransAssert((BPVector.size() > 1) && "Invalid Bracket Pairs!"); ArraySubTypeVector::const_reverse_iterator TyIdx = TyVec.rbegin(); unsigned LastSz = getArraySize(*TyIdx); ++TyIdx; const ArrayType *SecArrayTy = (*TyIdx); BracketLocPairVector::reverse_iterator BIdx = BPVector.rbegin(); BracketLocPair *LastBracketPair = (*BIdx); TheRewriter.RemoveText(SourceRange(LastBracketPair->first, LastBracketPair->second)); ++BIdx; BracketLocPair *SecBracketPair = (*BIdx); // We keep incomplete array if (!dyn_cast(SecArrayTy)) { // Keep this value, which is needed for rewriting ArraySubscriptExpr ArraySz = getArraySize(SecArrayTy); std::stringstream TmpSS; TmpSS << (LastSz * ArraySz); SourceLocation StartLoc = (SecBracketPair->first).getLocWithOffset(1); SourceLocation EndLoc = (SecBracketPair->second).getLocWithOffset(-1); TheRewriter.ReplaceText(SourceRange(StartLoc, EndLoc), TmpSS.str()); } freeBracketLocPairs(BPVector); Rewritten = true; return; } bool ReduceArrayDim::isIntegerExpr(const Expr *Exp) { const Expr *E = Exp->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::IntegerLiteralClass: case Expr::CharacterLiteralClass: // Fall-through return true; default: return false; } TransAssert(0 && "Unreachable code!"); return false; } void ReduceArrayDim::rewriteSubscriptExpr(const ExprVector &IdxExprs) { ExprVector::const_iterator I = IdxExprs.begin(); const Expr *LastE = (*I); ++I; const Expr *SecE = (*I); RewriteHelper->removeArraySubscriptExpr(LastE); int LastIdx = -1; int SecIdx = -1; if (isIntegerExpr(LastE)) LastIdx = getIndexAsInteger(LastE); if (isIntegerExpr(SecE)) SecIdx = getIndexAsInteger(SecE); if ((LastIdx >= 0) && (SecIdx >= 0)) { int NewIdx = (SecIdx * ArraySz + LastIdx); std::stringstream TmpSS; TmpSS << NewIdx; RewriteHelper->replaceExpr(SecE, TmpSS.str()); return; } std::string LastStr, SecStr, newStr; RewriteHelper->getExprString(LastE, LastStr); RewriteHelper->getExprString(SecE, SecStr); std::stringstream TmpSS; if (ArraySz == 1) { TmpSS << SecStr << "+" << LastStr; } else if (SecIdx == 1) { TmpSS << ArraySz << "+" << LastStr; } else { TmpSS << "(" << SecStr << ")*" << ArraySz << "+" << LastStr; } RewriteHelper->replaceExpr(SecE, TmpSS.str()); } void ReduceArrayDim::handleOneArraySubscriptExpr( const ArraySubscriptExpr *ASE) { const Type *ASETy = ASE->getType().getTypePtr(); if (!ASETy->isScalarType() && !ASETy->isStructureType() && !ASETy->isUnionType()) return; ExprVector IdxExprs; const Expr *BaseE = getBaseExprAndIdxExprs(ASE, IdxExprs); TransAssert(BaseE && "Empty Base expression!"); if (IdxExprs.size() <= 1) return; const DeclRefExpr *DRE = dyn_cast(BaseE); if (!DRE) return; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (CanonicalVD != TheVarDecl) return; rewriteSubscriptExpr(IdxExprs); Rewritten = true; } ReduceArrayDim::~ReduceArrayDim(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ReduceArrayDim.h000066400000000000000000000055001402162750500200750ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REDUCE_ARRAY_DIM_H #define REDUCE_ARRAY_DIM_H #include #include #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; class ArraySubscriptExpr; class ArrayType; } class ReduceArrayDimCollectionVisitor; class ReduceArrayDimRewriteVisitor; class ReduceArrayDim : public Transformation { friend class ReduceArrayDimCollectionVisitor; friend class ReduceArrayDimRewriteVisitor; public: ReduceArrayDim(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheVarDecl(NULL), ArraySz(0) { } ~ReduceArrayDim(void); private: typedef std::pair BracketLocPair; typedef llvm::SmallVector BracketLocPairVector; typedef llvm::SmallPtrSet VarDeclSet; typedef llvm::SmallVector InitListExprVector; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addOneVar(const clang::VarDecl *VD); void rewriteOneVarDecl(const clang::VarDecl *VD); void handleOneArraySubscriptExpr(const clang::ArraySubscriptExpr *ASE); void rewriteSubscriptExpr(const ExprVector &IdxExprs); void getBracketLocPairs(const clang::VarDecl *VD, unsigned int Dim, BracketLocPairVector &BPVec); void freeBracketLocPairs(BracketLocPairVector &BPVec); bool isIntegerExpr(const clang::Expr *E); void getInitListExprs(InitListExprVector &InitVec, const clang::InitListExpr *ILE, unsigned int Dim); void rewriteInitListExpr(const clang::InitListExpr *ILE, unsigned int Dim); unsigned getArraySize(const clang::ArrayType *ATy); VarDeclSet VisitedVarDecls; ReduceArrayDimCollectionVisitor *CollectionVisitor; ReduceArrayDimRewriteVisitor *RewriteVisitor; const clang::VarDecl *TheVarDecl; // for int a[1][2][3][4], ArraySz stores value 3 // It's used for computing indices of reduced ArraySubscriptExpr unsigned int ArraySz; // Unimplemented ReduceArrayDim(void); ReduceArrayDim(const ReduceArrayDim &); void operator=(const ReduceArrayDim &); }; #endif cvise-2.3.0/clang_delta/ReduceArraySize.cpp000066400000000000000000000201021402162750500206240ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2014, 2015, 2017, 2018, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReduceArraySize.h" #include #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Reduce the size of an array to the maximum index of \ accessing this array. Each transformation iteration \ works on one dimension for multidimensional arrays. \ This transformation is legitimate for an array if: \n\ * this array is ConstantArrayType; \n\ * and all indeices to this array are constants. \n"; static RegisterTransformation Trans("reduce-array-size", DescriptionMsg); class ReduceArraySizeCollectionVisitor : public RecursiveASTVisitor { public: explicit ReduceArraySizeCollectionVisitor(ReduceArraySize *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); private: ReduceArraySize *ConsumerInstance; }; bool ReduceArraySizeCollectionVisitor::VisitVarDecl(VarDecl *VD) { ConsumerInstance->handleOneVar(VD); return true; } bool ReduceArraySizeCollectionVisitor::VisitArraySubscriptExpr( ArraySubscriptExpr *ASE) { ConsumerInstance->handleOneASE(ASE); return true; } void ReduceArraySize::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReduceArraySizeCollectionVisitor(this); } bool ReduceArraySize::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void ReduceArraySize::HandleTranslationUnit(ASTContext &Ctx) { doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheVarDecl && "NULL TheVarDecl!"); TransAssert((TheDimValue >= 0) && "Bad TheDimValue!"); rewriteArrayVarDecl(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReduceArraySize::doAnalysis(void) { for (VarDeclToDimMap::iterator I = VarDeclToDim.begin(), E = VarDeclToDim.end(); I != E; ++I) { const VarDecl *VD = (*I).first; DimValueVector *DimVec = (*I).second; if (!DimVec) continue; DimValueVector *OrigDimVec = OrigVarDeclToDim[VD]; TransAssert(OrigDimVec && "Null OrigDimVec!"); unsigned int DimSz = DimVec->size(); TransAssert((DimSz == OrigDimVec->size()) && "Two DimValueVectors should have the same size!"); for (unsigned int II = 0; II < DimSz; ++II) { int DimV = (*DimVec)[II]; int OrigDimV = (*OrigDimVec)[II]; if ((DimV == -1) || (OrigDimV == 0) || ((DimV+1) == OrigDimV)) continue; ValidInstanceNum++; if (TransformationCounter != ValidInstanceNum) continue; TheVarDecl = VD; TheDimValue = DimV; TheDimIdx = II; } } } void ReduceArraySize::getBracketLocPair(const VarDecl *VD, unsigned int Dim, unsigned int DimIdx, BracketLocPair &LocPair) { SourceLocation StartLoc = VD->getLocation(); SourceLocation BPStartLoc, BPEndLoc; for (unsigned int I = 0; I < Dim; ++I) { BPStartLoc = RewriteHelper->getLocationUntil(StartLoc, '['); BPEndLoc = RewriteHelper->getLocationUntil(BPStartLoc, ']'); if (I == DimIdx) { LocPair.first = BPStartLoc; LocPair.second = BPEndLoc; break; } StartLoc = BPEndLoc; } } void ReduceArraySize::rewriteArrayVarDecl(void) { const Type *Ty = TheVarDecl->getType().getTypePtr(); const ArrayType *ArrayTy = dyn_cast(Ty); TransAssert(ArrayTy && "Invalid ArrayType!"); unsigned int Dim = getArrayDimension(ArrayTy); TransAssert((Dim > TheDimIdx) && "Bad Dimension Index!"); const VarDecl *FirstVD = TheVarDecl->getCanonicalDecl(); for(VarDecl::redecl_iterator RI = FirstVD->redecls_begin(), RE = FirstVD->redecls_end(); RI != RE; ++RI) { BracketLocPair LocPair; getBracketLocPair((*RI), Dim, TheDimIdx, LocPair); std::stringstream TmpSS; SourceLocation StartLoc = (LocPair.first).getLocWithOffset(1); SourceLocation EndLoc = (LocPair.second).getLocWithOffset(-1); TmpSS << (TheDimValue + 1); TheRewriter.ReplaceText(SourceRange(StartLoc, EndLoc), TmpSS.str()); } } void ReduceArraySize::handleOneVar(const VarDecl *VD) { if (isInIncludedFile(VD)) return; const Type *Ty = VD->getType().getTypePtr(); const ArrayType *ArrayTy = dyn_cast(Ty); if (!ArrayTy) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); DimValueVector *DimVec = VarDeclToDim[CanonicalVD]; if (DimVec) return; ArraySubTypeVector TyVec; unsigned int Dim = getArrayDimensionAndTypes(ArrayTy, TyVec); DimVec = new DimValueVector(Dim, -1); DimValueVector *OrigDimVec = new DimValueVector(Dim, -1); TransAssert((Dim == TyVec.size()) && "Unmatched Dimension and Array Sub Types!"); for (unsigned int I = 0; I < Dim; ++I) { const ConstantArrayType *CstArrayTy = dyn_cast(TyVec[I]); if (!CstArrayTy) { continue; } unsigned int InitSz = getConstArraySize(CstArrayTy); (*DimVec)[I] = 0; (*OrigDimVec)[I] = InitSz; } VarDeclToDim[CanonicalVD] = DimVec; OrigVarDeclToDim[CanonicalVD] = OrigDimVec; } bool ReduceArraySize::isIntegerExpr(const Expr *Exp) { const Expr *E = Exp->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::IntegerLiteralClass: case Expr::CharacterLiteralClass: // Fall-through return true; default: return false; } TransAssert(0 && "Unreachable code!"); return false; } void ReduceArraySize::handleOneASE(const ArraySubscriptExpr *ASE) { const Type *ASETy = ASE->getType().getTypePtr(); if (!ASETy->isScalarType() && !ASETy->isStructureType() && !ASETy->isUnionType()) return; ExprVector IdxExprs; const Expr *BaseE = getBaseExprAndIdxExprs(ASE, IdxExprs); TransAssert(BaseE && "Empty Base expression!"); const DeclRefExpr *DRE = dyn_cast(BaseE); if (!DRE) return; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); DimValueVector *DimVec = VarDeclToDim[CanonicalVD]; // It's possible DimVec is NULL, e.g., // int main(..., char *argv[]) { // ... argv[1] ... // } if (!DimVec) return; TransAssert((DimVec->size() >= IdxExprs.size()) && "More indices than it should be!"); unsigned int DimIdx = 0; for (ExprVector::reverse_iterator I = IdxExprs.rbegin(), E = IdxExprs.rend(); I != E; ++I) { int OldIdx = (*DimVec)[DimIdx]; if (OldIdx == -1) { DimIdx++; continue; } const Expr *IdxE = (*I); if (isIntegerExpr(IdxE)) { int Idx = getIndexAsInteger(IdxE); if (Idx > OldIdx) (*DimVec)[DimIdx] = Idx; } else { (*DimVec)[DimIdx] = -1; } DimIdx++; } } ReduceArraySize::~ReduceArraySize(void) { delete CollectionVisitor; for (VarDeclToDimMap::iterator I = VarDeclToDim.begin(), E = VarDeclToDim.end(); I != E; ++I) { delete (*I).second; } for (VarDeclToDimMap::iterator I = OrigVarDeclToDim.begin(), E = OrigVarDeclToDim.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/ReduceArraySize.h000066400000000000000000000046221402162750500203020ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REDUCE_ARRAY_SIZE_H #define REDUCE_ARRAY_SIZE_H #include #include #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; class ArraySubscriptExpr; class Expr; } class ReduceArraySizeCollectionVisitor; class ReduceArraySize : public Transformation { friend class ReduceArraySizeCollectionVisitor; public: ReduceArraySize(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheVarDecl(NULL), TheDimValue(-1), TheDimIdx(0) { } ~ReduceArraySize(void); private: typedef llvm::SmallVector DimValueVector; typedef llvm::MapVector VarDeclToDimMap; typedef std::pair BracketLocPair; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isIntegerExpr(const clang::Expr *Exp); void handleOneVar(const clang::VarDecl *VD); void handleOneASE(const clang::ArraySubscriptExpr *ASE); void doAnalysis(void); void rewriteArrayVarDecl(void); void getBracketLocPair(const clang::VarDecl *VD, unsigned int Dim, unsigned int DimIdx, BracketLocPair &LocPair); // if the value for a DimValue is -1, it means we cannot // reduce the size of the corresponding dimension VarDeclToDimMap VarDeclToDim; // Reference to the original DimValues // It is used to check if the maximum index is equal or // smaller than the size of an array VarDeclToDimMap OrigVarDeclToDim; ReduceArraySizeCollectionVisitor *CollectionVisitor; const clang::VarDecl *TheVarDecl; int TheDimValue; unsigned TheDimIdx; // Unimplemented ReduceArraySize(void); ReduceArraySize(const ReduceArraySize &); void operator=(const ReduceArraySize &); }; #endif cvise-2.3.0/clang_delta/ReduceClassTemplateParameter.cpp000066400000000000000000000606571402162750500233400ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReduceClassTemplateParameter.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass tries to remove one unused parameter from a class template \ declaration and also erase the corresponding template argument \ from template instantiations/specializations. Note that this pass \ does not target those templates with single argument, and skips \ variadic templates as well. "; static RegisterTransformation Trans("reduce-class-template-param", DescriptionMsg); class ReduceClassTemplateParameterASTVisitor : public RecursiveASTVisitor { public: explicit ReduceClassTemplateParameterASTVisitor( ReduceClassTemplateParameter *Instance) : ConsumerInstance(Instance) { } bool VisitClassTemplateDecl(ClassTemplateDecl *D); private: ReduceClassTemplateParameter *ConsumerInstance; }; namespace { typedef llvm::SmallPtrSet TemplateParameterSet; class TemplateParameterVisitor : public RecursiveASTVisitor { public: explicit TemplateParameterVisitor(TemplateParameterSet &Params) : UsedParameters(Params) { } ~TemplateParameterVisitor() { }; bool VisitTemplateTypeParmType(TemplateTypeParmType *Ty); private: TemplateParameterSet &UsedParameters; }; bool TemplateParameterVisitor::VisitTemplateTypeParmType( TemplateTypeParmType *Ty) { const TemplateTypeParmDecl *D = Ty->getDecl(); UsedParameters.insert(D); return true; } class ArgumentDependencyVisitor : public RecursiveASTVisitor { public: typedef llvm::DenseMap TypeToVisitsCountSet; explicit ArgumentDependencyVisitor(TypeToVisitsCountSet &CounterSet) : VisitsCountSet(CounterSet) { } bool VisitTemplateTypeParmType(TemplateTypeParmType *Ty); private: TypeToVisitsCountSet &VisitsCountSet; }; bool ArgumentDependencyVisitor::VisitTemplateTypeParmType( TemplateTypeParmType *Ty) { TypeToVisitsCountSet::iterator I = VisitsCountSet.find(Ty); if (I != VisitsCountSet.end()) { unsigned Count = (*I).second + 1; VisitsCountSet[(*I).first] = Count; } return true; } class ClassTemplateMethodVisitor : public RecursiveASTVisitor { public: ClassTemplateMethodVisitor(ReduceClassTemplateParameter *Instance, unsigned Idx) : ConsumerInstance(Instance), TheParameterIndex(Idx) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ReduceClassTemplateParameter *ConsumerInstance; unsigned TheParameterIndex; }; bool ClassTemplateMethodVisitor::VisitFunctionDecl(FunctionDecl *FD) { FunctionTemplateDecl *TD = FD->getDescribedFunctionTemplate(); for (FunctionDecl::redecl_iterator I = FD->redecls_begin(), E = FD->redecls_end(); I != E; ++I) { unsigned Num = (*I)->getNumTemplateParameterLists(); for (unsigned Idx = 0; Idx < Num; ++Idx) { const TemplateParameterList *TPList = (*I)->getTemplateParameterList(Idx); // We don't want to mistakenly rewrite template parameters associated // with the FD if FD is a function template. if (TD && TPList == TD->getTemplateParameters()) continue; const NamedDecl *Param = TPList->getParam(TheParameterIndex); SourceRange Range = Param->getSourceRange(); ConsumerInstance->removeParameterByRange(Range, TPList, TheParameterIndex); } } return true; } } class ReduceClassTemplateParameterRewriteVisitor : public RecursiveASTVisitor { public: explicit ReduceClassTemplateParameterRewriteVisitor( ReduceClassTemplateParameter *Instance) : ConsumerInstance(Instance) { } bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc Loc); private: ReduceClassTemplateParameter *ConsumerInstance; }; bool ReduceClassTemplateParameterRewriteVisitor:: VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc Loc) { // Invalidation can be introduced by constructor's initialization list, e.g.: // template class A { }; // class B : public A { // int m; // B(int x) : m(x) {} // }; // In RecursiveASTVisitor.h, TraverseConstructorInitializer will visit the part // of initializing base class's, i.e. through base's default constructor if (Loc.getBeginLoc().isInvalid()) return true; const TemplateSpecializationType *Ty = dyn_cast(Loc.getTypePtr()); TransAssert(Ty && "Invalid TemplateSpecializationType!"); TemplateName TmplName = Ty->getTemplateName(); if (!ConsumerInstance->referToTheTemplateDecl(TmplName)) return true; unsigned NumArgs = Loc.getNumArgs(); // I would put a stronger assert here, i.e., // " (ConsumerInstance->TheParameterIndex >= NumArgs) && // ConsumerInstance->hasDefaultArg " // but sometimes ill-formed input could yield incomplete // info, e.g., for two template decls which refer to the same // template def, one decl could have a non-null default arg, // while another decl's default arg field could be null. if (ConsumerInstance->TheParameterIndex >= NumArgs) return true; TransAssert((ConsumerInstance->TheParameterIndex < NumArgs) && "TheParameterIndex cannot be greater than NumArgs!"); TemplateArgumentLoc ArgLoc = Loc.getArgLoc(ConsumerInstance->TheParameterIndex); SourceRange Range = ArgLoc.getSourceRange(); if (NumArgs == 1) { ConsumerInstance->TheRewriter.ReplaceText(SourceRange(Loc.getLAngleLoc(), Loc.getRAngleLoc()), "<>"); } else if ((ConsumerInstance->TheParameterIndex + 1) == NumArgs) { SourceLocation EndLoc = Loc.getRAngleLoc(); EndLoc = EndLoc.getLocWithOffset(-1); ConsumerInstance->RewriteHelper->removeTextFromLeftAt( Range, ',', EndLoc); } else { ConsumerInstance->RewriteHelper->removeTextUntil(Range, ','); } return true; } bool ReduceClassTemplateParameterASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (ConsumerInstance->isInIncludedFile(D)) return true; ClassTemplateDecl *CanonicalD = D->getCanonicalDecl(); if (ConsumerInstance->VisitedDecls.count(CanonicalD)) return true; ConsumerInstance->VisitedDecls.insert(CanonicalD); if (!ConsumerInstance->isValidClassTemplateDecl(D)) return true; TemplateParameterSet ParamsSet; TemplateParameterVisitor ParameterVisitor(ParamsSet); CXXRecordDecl *CXXRD = D->getTemplatedDecl(); CXXRecordDecl *Def = CXXRD->getDefinition(); if (Def) ParameterVisitor.TraverseDecl(Def); // ISSUE: we should also check the parameter usage for partial template // specializations. For example: // template struct S{}; // template struct S{...}; // T1 or T2 could be used in "..." // Also, we could have another bad transformation, for example, // template struct S{}; // template struct S{}; // if we remove bool and true, we will have two definitions for S TemplateParameterList *TPList; if (Def) { // make sure we use the params as in ParameterVisitor const ClassTemplateDecl *CT = Def->getDescribedClassTemplate(); TransAssert(CT && "NULL DescribedClassTemplate!"); TPList = CT->getTemplateParameters(); } else { TPList = CanonicalD->getTemplateParameters(); } unsigned Index = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ND = (*I); if (ParamsSet.count(ND)) { Index++; continue; } ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheClassTemplateDecl = CanonicalD; ConsumerInstance->TheParameterIndex = Index; ConsumerInstance->TheTemplateName = new TemplateName(CanonicalD); ConsumerInstance->setDefaultArgFlag(ND); } Index++; } return true; } void ReduceClassTemplateParameter::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReduceClassTemplateParameterASTVisitor(this); ArgRewriteVisitor = new ReduceClassTemplateParameterRewriteVisitor(this); } void ReduceClassTemplateParameter::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheClassTemplateDecl && "NULL TheClassTemplateDecl!"); TransAssert(ArgRewriteVisitor && "NULL ArgRewriteVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); removeParameterFromDecl(); removeParameterFromMethods(); removeParameterFromPartialSpecs(); ArgRewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReduceClassTemplateParameter::removeParameterByRange(SourceRange Range, const TemplateParameterList *TPList, unsigned Index) { unsigned NumParams = TPList->size(); // if the parameter is the last one if (NumParams == 1) { TheRewriter.ReplaceText(SourceRange(TPList->getLAngleLoc(), TPList->getRAngleLoc()), "<>"); } else if ((Index + 1) == NumParams) { SourceLocation EndLoc = TPList->getRAngleLoc(); EndLoc = EndLoc.getLocWithOffset(-1); RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc); } else { RewriteHelper->removeTextUntil(Range, ','); } } void ReduceClassTemplateParameter::removeParameterFromDecl() { unsigned NumParams = TheClassTemplateDecl->getTemplateParameters()->size(); TransAssert((NumParams > 1) && "Bad size of TheClassTemplateDecl!"); (void)NumParams; for (ClassTemplateDecl::redecl_iterator I = TheClassTemplateDecl->redecls_begin(), E = TheClassTemplateDecl->redecls_end(); I != E; ++I) { const TemplateParameterList *TPList = (*I)->getTemplateParameters(); const NamedDecl *Param = TPList->getParam(TheParameterIndex); SourceRange Range = Param->getSourceRange(); removeParameterByRange(Range, TPList, TheParameterIndex); } } void ReduceClassTemplateParameter::removeParameterFromMethods() { CXXRecordDecl *CXXRD = TheClassTemplateDecl->getTemplatedDecl(); for (auto I = CXXRD->method_begin(), E = CXXRD->method_end(); I != E; ++I) { ClassTemplateMethodVisitor V(this, TheParameterIndex); V.TraverseDecl(*I); } } void ReduceClassTemplateParameter::removeOneParameterByArgExpression( const ClassTemplatePartialSpecializationDecl *PartialD, const TemplateArgument &Arg) { TransAssert((Arg.getKind() == TemplateArgument::Expression) && "Arg is not TemplateArgument::Expression!"); const Expr *E = Arg.getAsExpr(); TransAssert(E && "Bad Expression!"); const DeclRefExpr *DRE = dyn_cast(E->IgnoreParenCasts()); TransAssert(DRE && "Bad DeclRefExpr!"); const NonTypeTemplateParmDecl *ParmD = dyn_cast(DRE->getDecl()); TransAssert(ParmD && "Invalid NonTypeTemplateParmDecl!"); const TemplateParameterList *TPList = PartialD->getTemplateParameters(); unsigned Idx = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { if ((*I) == ParmD) break; Idx++; } unsigned NumParams = TPList->size(); TransAssert((Idx < NumParams) && "Cannot find valid TemplateParameter!"); (void)NumParams; SourceRange Range = ParmD->getSourceRange(); removeParameterByRange(Range, TPList, Idx); } void ReduceClassTemplateParameter::removeOneParameterByArgType( const ClassTemplatePartialSpecializationDecl *PartialD, const TemplateArgument &Arg) { TransAssert((Arg.getKind() == TemplateArgument::Type) && "Arg is not TemplateArgument::Type!"); llvm::DenseMap TypeToVisitsCount; llvm::DenseMap TypeToNamedDecl; llvm::DenseMap TypeToIndex; // retrieve all TemplateTypeParmType const TemplateParameterList *TPList = PartialD->getTemplateParameters(); unsigned Idx = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ND = (*I); const TemplateTypeParmDecl *TypeD = dyn_cast(ND); if (!TypeD) { Idx++; continue; } const Type *ParmTy = TypeD->getTypeForDecl(); TypeToVisitsCount[ParmTy] = 0; TypeToNamedDecl[ParmTy] = ND; TypeToIndex[ParmTy] = Idx; } QualType QTy = Arg.getAsType(); ArgumentDependencyVisitor V(TypeToVisitsCount); // collect TemplateTypeParmType being used by Arg V.TraverseType(QTy); llvm::DenseMap DependentTypeToVisitsCount; for (llvm::DenseMap::iterator I = TypeToVisitsCount.begin(), E = TypeToVisitsCount.end(); I != E; ++I) { if ((*I).second > 0) DependentTypeToVisitsCount[(*I).first] = 1; } // check if the used TemplateTypeParmType[s] have dependencies // on other Args. If yes, we cannot remove it from the parameter list. // For example: // template // struct S {}; // removing either of the arguments needs to keep the template // parameter ArgumentDependencyVisitor AccumV(DependentTypeToVisitsCount); const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); unsigned NumArgs = ArgList->NumTemplateArgs; TransAssert((TheParameterIndex < NumArgs) && "Bad NumArgs from partial template decl!"); for (unsigned I = 0; I < NumArgs; ++I) { if (I == TheParameterIndex) continue; const TemplateArgumentLoc ArgLoc = ArgLocs[I]; TemplateArgument OtherArg = ArgLoc.getArgument(); if (OtherArg.isInstantiationDependent() && (OtherArg.getKind() == TemplateArgument::Type)) { QualType QTy = OtherArg.getAsType(); AccumV.TraverseType(QTy); } } for (llvm::DenseMap::iterator I = DependentTypeToVisitsCount.begin(), E = DependentTypeToVisitsCount.end(); I != E; ++I) { if ((*I).second != 1) continue; const NamedDecl *Param = TypeToNamedDecl[(*I).first]; TransAssert(Param && "NULL Parameter!"); SourceRange Range = Param->getSourceRange(); removeParameterByRange(Range, TPList, TypeToIndex[(*I).first]); } } void ReduceClassTemplateParameter::removeOneParameterByArgTemplate( const ClassTemplatePartialSpecializationDecl *PartialD, const TemplateArgument &Arg) { TransAssert((Arg.getKind() == TemplateArgument::Template) && "Arg is not TemplateArgument::Template!"); TemplateName TmplName = Arg.getAsTemplate(); TransAssert((TmplName.getKind() == TemplateName::Template) && "Invalid TemplateName Kind!"); const TemplateDecl *TmplD = TmplName.getAsTemplateDecl(); const TemplateParameterList *TPList = PartialD->getTemplateParameters(); unsigned Idx = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { if ((*I) == TmplD) break; Idx++; } unsigned NumParams = TPList->size(); TransAssert((Idx < NumParams) && "Cannot find valid TemplateParameter!"); (void)NumParams; SourceRange Range = TmplD->getSourceRange(); removeParameterByRange(Range, TPList, Idx); return; } void ReduceClassTemplateParameter::removeOneParameterFromPartialDecl( const ClassTemplatePartialSpecializationDecl *PartialD, const TemplateArgument &Arg) { if (!Arg.isInstantiationDependent()) return; TemplateArgument::ArgKind K = Arg.getKind(); switch (K) { case TemplateArgument::Expression: removeOneParameterByArgExpression(PartialD, Arg); return; case TemplateArgument::Template: removeOneParameterByArgTemplate(PartialD, Arg); return; case TemplateArgument::Type: removeOneParameterByArgType(PartialD, Arg); return; default: TransAssert(0 && "Uncatched ArgKind!"); } TransAssert(0 && "Unreachable code!"); } const NamedDecl *ReduceClassTemplateParameter::getNamedDecl( const TemplateArgument &Arg) { if (!Arg.isInstantiationDependent()) return NULL; TemplateArgument::ArgKind K = Arg.getKind(); switch (K) { case TemplateArgument::Expression: { const Expr *E = Arg.getAsExpr(); if (const DeclRefExpr *DRE = dyn_cast(E)) { return dyn_cast(DRE->getDecl()); } else { return NULL; } } case TemplateArgument::Template: { TemplateName TmplName = Arg.getAsTemplate(); TransAssert((TmplName.getKind() == TemplateName::Template) && "Invalid TemplateName Kind!"); return TmplName.getAsTemplateDecl(); } case TemplateArgument::Type: { const Type *Ty = Arg.getAsType().getTypePtr(); if (const TemplateTypeParmType *TmplTy = dyn_cast(Ty)) { return TmplTy->getDecl(); } else { return NULL; } } default: return NULL; } TransAssert(0 && "Unreachable code!"); return NULL; } bool ReduceClassTemplateParameter::referToAParameter( const ClassTemplatePartialSpecializationDecl *PartialD, const TemplateArgument &Arg) { const NamedDecl *ArgND = getNamedDecl(Arg); if (!ArgND) return false; const TemplateParameterList *TPList = PartialD->getTemplateParameters(); for (TemplateParameterList::const_iterator PI = TPList->begin(), PE = TPList->end(); PI != PE; ++PI) { if (ArgND != (*PI)) return false; } return true; } bool ReduceClassTemplateParameter::isValidForReduction( const ClassTemplatePartialSpecializationDecl *PartialD) { const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); unsigned NumArgsAsWritten = ArgList->NumTemplateArgs; unsigned NumArgs = PartialD->getTemplateInstantiationArgs().size(); if ((NumArgsAsWritten > 0) && (TheParameterIndex >= NumArgsAsWritten) && hasDefaultArg && ((NumArgsAsWritten + 1) == NumArgs)) { return true; } if (NumArgsAsWritten != NumArgs) return false; const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); for (unsigned AI = 0; AI < NumArgsAsWritten; ++AI) { if (AI == TheParameterIndex) continue; const TemplateArgumentLoc ArgLoc = ArgLocs[AI]; TemplateArgument Arg = ArgLoc.getArgument(); if (!referToAParameter(PartialD, Arg)) return false; } return true; } bool ReduceClassTemplateParameter::reducePartialSpec( const ClassTemplatePartialSpecializationDecl *PartialD) { const CXXRecordDecl *CXXRD = TheClassTemplateDecl->getTemplatedDecl(); // it CXXRD has definition, skip it to avoid duplication if (CXXRD->hasDefinition()) return false; if (!isValidForReduction(PartialD)) return false; const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); unsigned NumArgsAsWritten = ArgList->NumTemplateArgs; const TemplateArgumentLoc FirstArgLoc = ArgLocs[0]; SourceRange FirstRange = FirstArgLoc.getSourceRange(); SourceLocation StartLoc = FirstRange.getBegin(); const TemplateArgumentLoc LastArgLoc = ArgLocs[NumArgsAsWritten - 1]; SourceRange LastRange = LastArgLoc.getSourceRange(); SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(LastRange, '>'); RewriteHelper->removeTextFromLeftAt(SourceRange(StartLoc, EndLoc), '<', EndLoc); return true; } // ISSUE: The transformation is known to go wrong in the following case: // template struct S; // template struct S; void ReduceClassTemplateParameter::removeParameterFromPartialSpecs() { SmallVector PartialDecls; TheClassTemplateDecl->getPartialSpecializations(PartialDecls); for (SmallVector::iterator I = PartialDecls.begin(), E = PartialDecls.end(); I != E; ++I) { const ClassTemplatePartialSpecializationDecl *PartialD = (*I); const ASTTemplateArgumentListInfo *ArgList = PartialD->getTemplateArgsAsWritten(); const TemplateArgumentLoc *ArgLocs = ArgList->getTemplateArgs(); unsigned NumArgs = ArgList->NumTemplateArgs; if (!ArgLocs) continue; // handle a special case where we could reduce a partial specialization // to a class template definition, e.g.: // template struct A; // template struct A { }; // ==> // template struct A; // template struct A { }; if (reducePartialSpec(PartialD)) continue; if ((TheParameterIndex >= NumArgs) && hasDefaultArg) return; TransAssert((TheParameterIndex < NumArgs) && "Bad NumArgs from partial template decl!"); TemplateArgumentLoc ArgLoc = ArgLocs[TheParameterIndex]; TemplateArgument Arg = ArgLoc.getArgument(); removeOneParameterFromPartialDecl(PartialD, Arg); SourceRange Range = ArgLoc.getSourceRange(); if (NumArgs == 1) { SourceLocation StartLoc = Range.getBegin(); SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(Range, '>'); EndLoc = EndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); } else if ((TheParameterIndex + 1) == NumArgs) { // Seems there is no getRAngleLoc() utility for // template arguments from a partial specialization SourceLocation EndLoc = RewriteHelper->getEndLocationUntil(Range, '>'); EndLoc = EndLoc.getLocWithOffset(-1); RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc); } else { RewriteHelper->removeTextUntil(Range, ','); } } } bool ReduceClassTemplateParameter::isValidClassTemplateDecl( const ClassTemplateDecl *D) { const TemplateParameterList *TPList = D->getTemplateParameters(); if (TPList->size() <= 1) return false; // FIXME: need to handle parameter pack later for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { if (isParameterPack(*I)) return false; } return true; } void ReduceClassTemplateParameter::setDefaultArgFlag(const NamedDecl *ND) { if (const NonTypeTemplateParmDecl *D = dyn_cast(ND)) { hasDefaultArg = D->hasDefaultArgument(); } else if (const TemplateTypeParmDecl *D = dyn_cast(ND)) { hasDefaultArg = D->hasDefaultArgument(); } else if (const TemplateTemplateParmDecl *D = dyn_cast(ND)) { hasDefaultArg = D->hasDefaultArgument(); } else { TransAssert(0 && "Unknown template parameter type!"); } } bool ReduceClassTemplateParameter::referToTheTemplateDecl( TemplateName TmplName) { return Context->hasSameTemplateName(*TheTemplateName, TmplName); } ReduceClassTemplateParameter::~ReduceClassTemplateParameter() { delete TheTemplateName; delete CollectionVisitor; delete ArgRewriteVisitor; } cvise-2.3.0/clang_delta/ReduceClassTemplateParameter.h000066400000000000000000000071461402162750500227770ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REDUCE_CLASS_TEMPLATE_PARAMETER_H #define REDUCE_CLASS_TEMPLATE_PARAMETER_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class ClassTemplateDecl; class NamedDecl; class TemplateName; class TemplateArgument; class ClassTemplatePartialSpecializationDecl; class TemplateParameterList; } class ReduceClassTemplateParameterASTVisitor; class ReduceClassTemplateParameterRewriteVisitor; class ReduceClassTemplateParameter : public Transformation { friend class ReduceClassTemplateParameterASTVisitor; friend class ReduceClassTemplateParameterRewriteVisitor; public: ReduceClassTemplateParameter(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), ArgRewriteVisitor(NULL), TheClassTemplateDecl(NULL), hasDefaultArg(false), TheParameterIndex(0), TheTemplateName(NULL) {} ~ReduceClassTemplateParameter(); void removeParameterByRange(clang::SourceRange Range, const clang::TemplateParameterList *TPList, unsigned Index); private: typedef llvm::SmallPtrSet ClassTemplateDeclSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void setDefaultArgFlag(const clang::NamedDecl *ND); bool isValidClassTemplateDecl(const clang::ClassTemplateDecl *D); void removeParameterFromDecl(); void removeParameterFromMethods(); void removeParameterFromPartialSpecs(); void removeOneParameterFromPartialDecl( const clang::ClassTemplatePartialSpecializationDecl *PartialD, const clang::TemplateArgument &Arg); void removeOneParameterByArgExpression( const clang::ClassTemplatePartialSpecializationDecl *PartialD, const clang::TemplateArgument &Arg); void removeOneParameterByArgType( const clang::ClassTemplatePartialSpecializationDecl *PartialD, const clang::TemplateArgument &Arg); void removeOneParameterByArgTemplate( const clang::ClassTemplatePartialSpecializationDecl *PartialD, const clang::TemplateArgument &Arg); void removeArgumentFromSpecializations(); bool referToTheTemplateDecl(clang::TemplateName TmplName); bool reducePartialSpec( const clang::ClassTemplatePartialSpecializationDecl *PartialD); bool isValidForReduction( const clang::ClassTemplatePartialSpecializationDecl *PartialD); bool referToAParameter( const clang::ClassTemplatePartialSpecializationDecl *PartialD, const clang::TemplateArgument &Arg); const clang::NamedDecl *getNamedDecl(const clang::TemplateArgument &Arg); ClassTemplateDeclSet VisitedDecls; ReduceClassTemplateParameterASTVisitor *CollectionVisitor; ReduceClassTemplateParameterRewriteVisitor *ArgRewriteVisitor; clang::ClassTemplateDecl *TheClassTemplateDecl; bool hasDefaultArg; unsigned TheParameterIndex; clang::TemplateName *TheTemplateName; // Unimplemented ReduceClassTemplateParameter(); ReduceClassTemplateParameter(const ReduceClassTemplateParameter &); void operator=(const ReduceClassTemplateParameter &); }; #endif cvise-2.3.0/clang_delta/ReducePointerLevel.cpp000066400000000000000000000676071402162750500213500ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReducePointerLevel.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Reduce pointer indirect level for a global/local variable. \ All valid variables are sorted by their indirect levels. \ The pass will ensure to first choose a valid variable \ with the largest indirect level. This approach could \ reduce the complexity of our implementation, because \ we don't have to consider the case where the chosen variable \ with the largest indirect level would be address-taken. \ Variables at non-largest-indirect-level are ineligible \ if they: \n\ * being address-taken \n\ * OR being used as LHS in any pointer form, e.g., \n\ p, *p(assume *p is of pointer type), \n\ while the RHS is NOT a UnaryOperator. \n"; static RegisterTransformation Trans("reduce-pointer-level", DescriptionMsg); class PointerLevelCollectionVisitor : public RecursiveASTVisitor { public: explicit PointerLevelCollectionVisitor(ReducePointerLevel *Instance) : ConsumerInstance(Instance) { } bool VisitDeclaratorDecl(DeclaratorDecl *DD); bool VisitUnaryOperator(UnaryOperator *UO); bool VisitBinaryOperator(BinaryOperator *BO); private: ReducePointerLevel *ConsumerInstance; int getPointerIndirectLevel(const Type *Ty); bool isVAArgField(DeclaratorDecl *DD); }; class PointerLevelRewriteVisitor : public RecursiveASTVisitor { public: explicit PointerLevelRewriteVisitor(ReducePointerLevel *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitFieldDecl(FieldDecl *FD); bool VisitUnaryOperator(UnaryOperator *UO); bool VisitBinaryOperator(BinaryOperator *BO); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitMemberExpr(MemberExpr *ME); bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *ME); private: ReducePointerLevel *ConsumerInstance; }; int PointerLevelCollectionVisitor::getPointerIndirectLevel(const Type *Ty) { int IndirectLevel = 0; QualType QT = Ty->getPointeeType(); while (!QT.isNull()) { IndirectLevel++; QT = QT.getTypePtr()->getPointeeType(); } return IndirectLevel; } // Any better way to ginore these two fields // coming from __builtin_va_arg ? bool PointerLevelCollectionVisitor::isVAArgField(DeclaratorDecl *DD) { std::string Name = DD->getNameAsString(); return (!Name.compare("reg_save_area") || !Name.compare("overflow_arg_area")); } // I skipped IndirectFieldDecl for now bool PointerLevelCollectionVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { if (ConsumerInstance->isInIncludedFile(DD) || isVAArgField(DD)) return true; // Only consider FieldDecl and VarDecl Decl::Kind K = DD->getKind(); if ((K != Decl::Field) && (K != Decl::Var)) return true; const Type *Ty = DD->getType().getTypePtr(); // omit SubstTemplateTypeParmType for now, .e.g., // template // void foo(T last) { T t; } // void bar(void) { int a; foo(&a); } // in this example, T is inferred as int *, // but we cannot do anything useful for "T t" if (dyn_cast(Ty)) return true; // skip AutoType for now if (Ty->getContainedAutoType()) return true; if (const ArrayType *ArrayTy = dyn_cast(Ty)) Ty = ConsumerInstance->getArrayBaseElemType(ArrayTy); if (!Ty->isPointerType() || Ty->isVoidPointerType()) return true; const Type *PointeeTy = Ty->getPointeeType().getTypePtr(); if (PointeeTy->isIncompleteType() || ConsumerInstance->isPointerToSelf(PointeeTy, DD)) return true; DeclaratorDecl *CanonicalDD = dyn_cast(DD->getCanonicalDecl()); TransAssert(CanonicalDD && "Bad DeclaratorDecl!"); if (ConsumerInstance->VisitedDecls.count(CanonicalDD)) return true; ConsumerInstance->ValidDecls.insert(CanonicalDD); ConsumerInstance->VisitedDecls.insert(CanonicalDD); int IndirectLevel = getPointerIndirectLevel(Ty); TransAssert((IndirectLevel > 0) && "Bad indirect level!"); if (IndirectLevel > ConsumerInstance->MaxIndirectLevel) ConsumerInstance->MaxIndirectLevel = IndirectLevel; ConsumerInstance->addOneDecl(CanonicalDD, IndirectLevel); return true; } bool PointerLevelCollectionVisitor::VisitUnaryOperator(UnaryOperator *UO) { UnaryOperator::Opcode Op = UO->getOpcode(); if (Op == UO_Deref) { ConsumerInstance->checkPrefixAndPostfix(UO); return true; } if (Op != UO_AddrOf) return true; const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); if (!dyn_cast(SubE) && !dyn_cast(SubE) && !dyn_cast(SubE)) return true; if (const DeclaratorDecl *DD = ConsumerInstance->getRefDecl(SubE)) ConsumerInstance->AddrTakenDecls.insert(DD); return true; } bool PointerLevelCollectionVisitor::VisitBinaryOperator(BinaryOperator *BO) { if (!BO->isAssignmentOp() && !BO->isCompoundAssignmentOp()) return true; Expr *Lhs = BO->getLHS(); const Type *Ty = Lhs->getType().getTypePtr(); if (!Ty->isPointerType()) return true; Expr *Rhs = BO->getRHS()->IgnoreParenCasts(); if (dyn_cast(Rhs) || dyn_cast(Rhs) || dyn_cast(Rhs) || dyn_cast(Rhs) || dyn_cast(Rhs) || dyn_cast(Rhs)) return true; const DeclaratorDecl *DD = ConsumerInstance->getRefDecl(Lhs); TransAssert(DD && "NULL DD!"); ConsumerInstance->ValidDecls.erase(DD); return true; } bool PointerLevelRewriteVisitor::VisitFieldDecl(FieldDecl *FD) { const FieldDecl *TheFD = dyn_cast(ConsumerInstance->TheDecl); // TheDecl is a VarDecl if (!TheFD) return true; const FieldDecl *CanonicalFD = dyn_cast(FD->getCanonicalDecl()); if (CanonicalFD == TheFD) ConsumerInstance->rewriteFieldDecl(FD); return true; } bool PointerLevelRewriteVisitor::VisitVarDecl(VarDecl *VD) { const VarDecl *TheVD = dyn_cast(ConsumerInstance->TheDecl); if (TheVD) { const VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (CanonicalVD == TheVD) { ConsumerInstance->rewriteVarDecl(VD); } // Because VD must not be addr-taken, we don't have cases like: // int **p2 = &p1; // where p1 is TheVD // It's safe to return from here. return true; } // TheDecl is a FieldDecl. // But we still need to handle VarDecls which are type of // struct/union where TheField could reside, if these VarDecls // have initializers if (!VD->hasInit()) return true; const Type *VDTy = VD->getType().getTypePtr(); if (!VDTy->isAggregateType()) return true; if (const ArrayType *ArrayTy = dyn_cast(VDTy)) { const Type *ArrayElemTy = ConsumerInstance->getArrayBaseElemType(ArrayTy); if (!ArrayElemTy->isStructureType() && !ArrayElemTy->isUnionType()) return true; if (const RecordType *RDTy = ArrayElemTy->getAs()) { const RecordDecl *RD = RDTy->getDecl(); ConsumerInstance->rewriteArrayInit(RD, VD->getInit()); } return true; } if (const RecordType *RDTy = VDTy->getAs()) { const RecordDecl *RD = RDTy->getDecl(); ConsumerInstance->rewriteRecordInit(RD, VD->getInit()); } return true; } bool PointerLevelRewriteVisitor::VisitUnaryOperator(UnaryOperator *UO) { UnaryOperator::Opcode Op = UO->getOpcode(); if (Op != UO_Deref) return true; const Expr *SubE = UO->getSubExpr(); const DeclaratorDecl *DD = ConsumerInstance->getRefDecl(SubE); if (DD != ConsumerInstance->TheDecl) return true; const DeclRefExpr *DRE = ConsumerInstance->getDeclRefExpr(SubE); if (DRE) { if (ConsumerInstance->VisitedDeclRefExprs.count(DRE)) return true; ConsumerInstance->VisitedDeclRefExprs.insert(DRE); } else { const MemberExpr *ME = dyn_cast(SubE); if (ConsumerInstance->VisitedMemberExprs.count(ME)) return true; ConsumerInstance->VisitedMemberExprs.insert(ME); } ConsumerInstance->rewriteDerefOp(UO); return true; } bool PointerLevelRewriteVisitor::VisitBinaryOperator(BinaryOperator *BO) { if (!BO->isAssignmentOp() && !BO->isCompoundAssignmentOp()) return true; const Expr *Lhs = BO->getLHS(); // Lhs could be CallExpr if (dyn_cast(Lhs) || dyn_cast(Lhs) || dyn_cast(Lhs)) return true; const DeclaratorDecl *DD = ConsumerInstance->getRefDecl(Lhs); // it's not always we could have a nonnull DD // TransAssert(DD && "NULL DD!"); if (DD != ConsumerInstance->TheDecl) return true; const DeclRefExpr *DRE = ConsumerInstance->getDeclRefExpr(Lhs); if (DRE) { if (ConsumerInstance->VisitedDeclRefExprs.count(DRE)) return true; ConsumerInstance->VisitedDeclRefExprs.insert(DRE); } else { const MemberExpr *ME = dyn_cast(Lhs); if (ConsumerInstance->VisitedMemberExprs.count(ME)) return true; ConsumerInstance->VisitedMemberExprs.insert(ME); } const Expr *Rhs = BO->getRHS(); const Type *Ty = Lhs->getType().getTypePtr(); if (Ty->isPointerType()) { // Prefer removing a '*' on LHS, because it's less-likely to generate // bad code, e.g., // int *a, **c = &a, d, *f = &d; // **c = f; // if we change the code above to: // **c = *f; // **c is a derefence to a NULL pointer. // On the other hand, *c = f is still valid. const Expr *DirectLhs = Lhs->IgnoreParenCasts(); const UnaryOperator *LhsUO = dyn_cast(DirectLhs); if (LhsUO && (LhsUO->getOpcode() == UO_Deref)) { return ConsumerInstance->RewriteHelper->removeAStarAfter(Lhs); } const Expr *DirectRhs = Rhs->IgnoreParenCasts(); const UnaryOperator *UO = dyn_cast(DirectRhs); if (UO && (UO->getOpcode() == UO_AddrOf)) { return ConsumerInstance->RewriteHelper->removeAnAddrOfAfter(Rhs); } return ConsumerInstance->RewriteHelper->insertAStarBefore(Rhs); } else if (Ty->isStructureType() || Ty->isUnionType() || Ty->isIntegerType()) { if (const ArraySubscriptExpr *ASE = dyn_cast(Lhs)) return ConsumerInstance->RewriteHelper->removeArraySubscriptExpr( ASE->getIdx()); else return ConsumerInstance->RewriteHelper->removeAStarAfter(Lhs); } return true; } bool PointerLevelRewriteVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { const ValueDecl *OrigDecl = DRE->getDecl(); if (dyn_cast(OrigDecl)) return true; const DeclaratorDecl *DD = dyn_cast(OrigDecl); TransAssert(DD && "Bad VarDecl!"); if ((DD == ConsumerInstance->TheDecl) && !(ConsumerInstance->VisitedDeclRefExprs.count(DRE))) { // FIXME: handle cases below // int foo(void) { int *a; return a[0]; } ConsumerInstance->rewriteDeclRefExpr(DRE); } return true; } bool PointerLevelRewriteVisitor::VisitMemberExpr(MemberExpr *ME) { if (ConsumerInstance->VisitedMemberExprs.count(ME)) return true; const ValueDecl *OrigDecl = ME->getMemberDecl(); const DeclaratorDecl *DD = dyn_cast(OrigDecl); if (!DD) return true; DD = dyn_cast(DD->getCanonicalDecl()); TransAssert(DD && "Bad DeclaratorDecl!"); if (DD == ConsumerInstance->TheDecl) { ConsumerInstance->RewriteHelper->insertAnAddrOfBefore(ME); return true; } // change x->y to x.y if x is TheDecl if (!ME->isArrow()) return true; const Expr *Base = ME->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast(Base)) { OrigDecl = DRE->getDecl(); DD = dyn_cast(OrigDecl); TransAssert(DD && "Bad VarDecl!"); if (DD == ConsumerInstance->TheDecl) { ConsumerInstance->VisitedDeclRefExprs.insert(DRE); ConsumerInstance->replaceArrowWithDot(ME); } return true; } if (const MemberExpr *BaseME = dyn_cast(Base)) { OrigDecl = BaseME->getMemberDecl(); DD = dyn_cast(OrigDecl); TransAssert(DD && "Bad FieldDecl!"); if (DD == ConsumerInstance->TheDecl) { ConsumerInstance->VisitedMemberExprs.insert(BaseME); ConsumerInstance->replaceArrowWithDot(ME); } } return true; } bool PointerLevelRewriteVisitor::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *ME) { if (ME->isImplicitAccess()) return true; const Expr *Base = ME->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast(Base)) { const DeclaratorDecl *DD = dyn_cast(DRE->getDecl()); TransAssert(DD && "Bad VarDecl!"); if (DD == ConsumerInstance->TheDecl) { ConsumerInstance->VisitedDeclRefExprs.insert(DRE); ConsumerInstance->replaceArrowWithDot(ME); } } return true; } void ReducePointerLevel::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new PointerLevelCollectionVisitor(this); RewriteVisitor = new PointerLevelRewriteVisitor(this); } void ReducePointerLevel::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); TransAssert(RewriteVisitor && "NULL CollectionVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheDecl && "NULL TheDecl!"); setRecordDecl(); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReducePointerLevel::doAnalysis(void) { DeclSet *Decls; Decls = AllPtrDecls[MaxIndirectLevel]; if (Decls) { for (DeclSet::const_iterator I = Decls->begin(), E = Decls->end(); I != E; ++I) { if (!ValidDecls.count(*I)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) TheDecl = *I; } } for (int Idx = MaxIndirectLevel - 1; Idx > 0; --Idx) { Decls = AllPtrDecls[Idx]; if (!Decls) continue; for (DeclSet::const_iterator I = Decls->begin(), E = Decls->end(); I != E; ++I) { if (!ValidDecls.count(*I) || AddrTakenDecls.count(*I)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) TheDecl = *I; } } } void ReducePointerLevel::setRecordDecl(void) { const FieldDecl *TheFD = dyn_cast(TheDecl); if (!TheFD) return; TheRecordDecl = TheFD->getParent(); } const DeclRefExpr *ReducePointerLevel::getDeclRefExpr(const Expr *Exp) { const Expr *E = ignoreSubscriptExprParenCasts(Exp); if (const DeclRefExpr *DRE = dyn_cast(E)) return DRE; if (dyn_cast(E)) { return NULL; } const UnaryOperator *UO = dyn_cast(E); TransAssert(UO && "Bad UnaryOperator!"); UnaryOperator::Opcode Op = UO->getOpcode(); (void)Op; TransAssert(((Op == UO_Deref) || (Op == UO_AddrOf)) && "Invalid Unary Opcode!"); const Expr *SubE = UO->getSubExpr(); return getDeclRefExpr(SubE); } const DeclaratorDecl *ReducePointerLevel::getRefDecl(const Expr *Exp) { const Expr *E = ignoreSubscriptExprParenCasts(Exp); if (dyn_cast(E)) return NULL; if (const DeclRefExpr *DRE = dyn_cast(E)) return getCanonicalDeclaratorDecl(DRE); if (const MemberExpr *ME = dyn_cast(E)) return getCanonicalDeclaratorDecl(ME); const UnaryOperator *UO = dyn_cast(E); // In some case, E could not be of UO if the program under transformation // is invalid. if (!UO) return NULL; const Expr *SubE = UO->getSubExpr(); return getRefDecl(SubE); } void ReducePointerLevel::checkPrefixAndPostfix(const UnaryOperator *UO) { const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); const UnaryOperator *SubUO = dyn_cast(SubE); if (!SubUO) return; if (!SubUO->isPrefix() && !SubUO->isPostfix()) return; const DeclaratorDecl *DD = getRefDecl(SubUO->getSubExpr()); if (DD) { ValidDecls.erase(DD); } } void ReducePointerLevel::addOneDecl(const DeclaratorDecl *DD, int IndirectLevel) { DeclSet *DDSet = AllPtrDecls[IndirectLevel]; if (!DDSet) { DDSet = new DeclSet(); AllPtrDecls[IndirectLevel] = DDSet; } DDSet->insert(DD); } const DeclaratorDecl * ReducePointerLevel::getCanonicalDeclaratorDecl(const Expr *E) { const DeclaratorDecl *DD = NULL; if (const DeclRefExpr *DRE = dyn_cast(E)) { const ValueDecl *ValueD = DRE->getDecl(); DD = dyn_cast(ValueD); if (!DD) return NULL; } else if (const MemberExpr *ME = dyn_cast(E)) { ValueDecl *OrigDecl = ME->getMemberDecl(); // in C++, getMemberDecl returns a CXXMethodDecl. TransAssert(isa(OrigDecl) && "Unsupported C++ getMemberDecl!\n"); DD = dyn_cast(OrigDecl); } else { TransAssert(0 && "Bad Decl!"); } const DeclaratorDecl *CanonicalDD = dyn_cast(DD->getCanonicalDecl()); TransAssert(CanonicalDD && "NULL CanonicalDD!"); return CanonicalDD; } const Expr *ReducePointerLevel::getFirstInitListElem(const InitListExpr *ILE) { const Expr *E = NULL; unsigned InitNum = ILE->getNumInits(); for (unsigned int I = 0; I < InitNum; ++I) { E = ILE->getInit(I); ILE = dyn_cast(E); if (ILE) { E = getFirstInitListElem(ILE); } if (E) return E; } return NULL; } void ReducePointerLevel::copyInitStr(const Expr *Exp, std::string &InitStr) { const Expr *E = Exp->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::DeclRefExprClass: { const DeclRefExpr *DRE = dyn_cast(E); const ValueDecl *OrigDecl = DRE->getDecl(); if (dyn_cast(OrigDecl)) { InitStr = "0"; return; } const VarDecl *VD = dyn_cast(OrigDecl); TransAssert(VD && "Bad VarDecl!"); const Expr *InitE = VD->getAnyInitializer(); if (!InitE) { const Type *Ty = VD->getType().getTypePtr(); if (Ty->isIntegerType() || Ty->isPointerType()) InitStr = "0"; return; } const Type *VT = VD->getType().getTypePtr(); const ArrayType *AT = dyn_cast(VT); if (AT) { const InitListExpr *ILE = dyn_cast(InitE); if (ILE) { const Expr *ElemE = getFirstInitListElem(ILE); if (!ElemE) return; InitE = ElemE; } } RewriteHelper->getExprString(InitE, InitStr); return; } case Expr::ArraySubscriptExprClass: { const ArraySubscriptExpr *ASE = dyn_cast(E); if (const Expr *ElemE = getArraySubscriptElem(ASE)) RewriteHelper->getExprString(ElemE, InitStr); return; } case Expr::MemberExprClass: { const MemberExpr *ME = dyn_cast(E); if (const Expr *ElemE = getMemberExprElem(ME)) RewriteHelper->getExprString(ElemE, InitStr); return; } default: TransAssert(0 && "Uncatched initializer!"); } TransAssert(0 && "Unreachable code!"); } void ReducePointerLevel::getInitListExprString(const InitListExpr *ILE, std::string &NewInitStr, InitListHandler Handler) { unsigned int NumInits = ILE->getNumInits(); NewInitStr = "{"; for (unsigned int I = 0; I < NumInits; ++I) { const Expr *SubInitE = ILE->getInit(I); std::string SubInitStr(""); (this->*Handler)(SubInitE, SubInitStr); if (SubInitStr == "") { NewInitStr = "{}"; return; } if (I == 0) NewInitStr += SubInitStr; else NewInitStr += ("," + SubInitStr); } NewInitStr += "}"; return; } void ReducePointerLevel::getNewGlobalInitStr(const Expr *Init, std::string &InitStr) { const Expr *E = Init->IgnoreParenCasts(); switch(E->getStmtClass()) { case Expr::IntegerLiteralClass: RewriteHelper->getExprString(Init, InitStr); return; case Expr::StringLiteralClass: InitStr = 'a'; return; case Expr::UnaryOperatorClass: { const UnaryOperator *UO = dyn_cast(E); TransAssert((UO->getOpcode() == UO_AddrOf) && "Non-Unary Operator!"); const Expr *SubE = UO->getSubExpr(); TransAssert(SubE && "Bad Sub Expr!"); // Now we try to get the init string of this addr-taken var/array_var/field copyInitStr(SubE, InitStr); return; } case Expr::InitListExprClass: { const InitListExpr *ILE = dyn_cast(E); getInitListExprString(ILE, InitStr, &ReducePointerLevel::getNewGlobalInitStr); return; } case Expr::DeclRefExprClass: { const DeclRefExpr *DRE = dyn_cast(E); copyInitStr(DRE, InitStr); return; } // it could happen if E is call to a static method of a class case Expr::CallExprClass: { const CallExpr *CE = dyn_cast(E); const FunctionDecl *FD = CE->getDirectCallee(); TransAssert(FD && "Invalid Function Decl!"); const CXXMethodDecl *MDecl = dyn_cast(FD); (void)MDecl; TransAssert(MDecl->isStatic() && "Non static CXXMethodDecl!"); InitStr = ""; return; } case Expr::CXXNewExprClass: { InitStr = ""; return; } default: TransAssert(0 && "Uncatched initializer!"); } TransAssert(0 && "Unreachable code!"); } void ReducePointerLevel::getNewLocalInitStr(const Expr *Init, std::string &InitStr) { const Expr *E = Init->IgnoreParenCasts(); switch(E->getStmtClass()) { // catch the case like int *p = 0; case Expr::IntegerLiteralClass: RewriteHelper->getExprString(E, InitStr); return; // FIXME: not quite correct to set the InitStr to an empty string case Expr::GNUNullExprClass: InitStr = ""; return; case Expr::CXXNewExprClass: case Expr::CXXNullPtrLiteralExprClass: // Fall-through InitStr = ""; return; case Expr::StringLiteralClass: InitStr = 'a'; return; case Expr::ConditionalOperatorClass: InitStr = ""; return; case Expr::StmtExprClass: InitStr = ""; return; case Expr::UnaryOperatorClass: { const UnaryOperator *UO = dyn_cast(E); TransAssert(UO->getSubExpr() && "Bad Sub Expr!"); RewriteHelper->getExprString(E, InitStr); size_t Pos; UnaryOperator::Opcode Op = UO->getOpcode(); if (Op == UO_AddrOf) { Pos = InitStr.find_first_of('&'); TransAssert((Pos != std::string::npos) && "No & operator!"); InitStr.erase(Pos, 1); } else if (Op == UO_Deref) { Pos = InitStr.find_first_of('*'); TransAssert((Pos != std::string::npos) && "No & operator!"); InitStr.insert(Pos, "*"); } else { TransAssert(0 && "Bad UnaryOperator!"); } return; } case Expr::DeclRefExprClass: { const DeclRefExpr *DE = dyn_cast(E); RewriteHelper->getExprString(E, InitStr); const Type *VT = DE->getType().getTypePtr(); // handle case like: // int a[10]; // int *p = (int*)a; if (const ArrayType *AT = dyn_cast(VT)) { unsigned int Dim = getArrayDimension(AT); std::string ArrayElemsStr(""); for (unsigned int I = 0; I < Dim; ++I) { ArrayElemsStr += "[0]"; } InitStr += ArrayElemsStr; } else { InitStr = "*" + InitStr; } return; } case Expr::MemberExprClass: // Fall-through case Expr::BinaryOperatorClass: case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: case Expr::CallExprClass: case Expr::ArraySubscriptExprClass: { RewriteHelper->getExprString(E, InitStr); InitStr = "*(" + InitStr + ")"; return; } case Expr::InitListExprClass: { const InitListExpr *ILE = dyn_cast(E); getInitListExprString(ILE, InitStr, &ReducePointerLevel::getNewLocalInitStr); return; } case Expr::CXXScalarValueInitExprClass: RewriteHelper->getExprString(E, InitStr); return; default: TransAssert(0 && "Uncaught initializer!"); } TransAssert(0 && "Unreachable code!"); } void ReducePointerLevel::rewriteVarDecl(const VarDecl *VD) { RewriteHelper->removeAStarBefore(VD); const Expr *Init = VD->getInit(); if (!Init) return; const Type *Ty = VD->getType().getTypePtr(); if (Ty->isPointerType()) { const Type *PointeeTy = Ty->getPointeeType().getTypePtr(); if (PointeeTy->isRecordType()) { const Expr *E = Init->IgnoreParenCasts(); Expr::StmtClass SC = E->getStmtClass(); if ((SC == Expr::IntegerLiteralClass) || (SC == Expr::StringLiteralClass)) { RewriteHelper->removeVarInitExpr(VD); return; } } } std::string NewInitStr(""); if (VD->hasLocalStorage()) { getNewLocalInitStr(Init, NewInitStr); } else { // Global var cannot have non-const initializer, // e.g., "int *p = &g;" ==> "int p = g" is invalid. // So we need to do more work. // Get the init string of RHS var: // The transformation will look like: // (1) int g = 1; // int *p = &g; ==> int p = 1; // (2) int g[2] = {1, 2}; // int *p = &g[1]; ==> int p = 2; // (2) int g[2] = {1, 2}; // int *p = &g; ==> int p = 1; // (4) struct S g = {1, 2}; // int *p = &g.f1; ==> int p = 1; getNewGlobalInitStr(Init, NewInitStr); } if (NewInitStr.empty()) RewriteHelper->removeVarInitExpr(VD); else RewriteHelper->replaceExpr(Init, NewInitStr); } void ReducePointerLevel::rewriteFieldDecl(const FieldDecl *FD) { RewriteHelper->removeAStarBefore(FD); } void ReducePointerLevel::rewriteDerefOp(const UnaryOperator *UO) { RewriteHelper->removeAStarAfter(UO); } void ReducePointerLevel::rewriteDeclRefExpr(const DeclRefExpr *DRE) { RewriteHelper->insertAnAddrOfBefore(DRE); } void ReducePointerLevel::replaceArrowWithDot(const Expr *E) { std::string ES; RewriteHelper->getExprString(E, ES); SourceLocation LocStart = E->getBeginLoc(); size_t ArrowPos = ES.find("->"); TransAssert((ArrowPos != std::string::npos) && "Cannot find Arrow!"); LocStart = LocStart.getLocWithOffset(ArrowPos); TheRewriter.ReplaceText(LocStart, 2, "."); } bool ReducePointerLevel::isPointerToSelf(const Type *Ty, const DeclaratorDecl *DD) { const RecordType *RTy = Ty->getAs(); if (!RTy) return false; const DeclContext *Ctx = DD->getDeclContext(); const RecordDecl *RD = dyn_cast(Ctx); if (!RD) return false; const RecordDecl *NestedRD = RTy->getDecl(); return (RD->getCanonicalDecl() == NestedRD->getCanonicalDecl()); } void ReducePointerLevel::rewriteRecordInit(const RecordDecl *RD, const Expr *Init) { // FIXME: Csmith doesn't have pointer fields, I will // leave this function as future work } void ReducePointerLevel::rewriteArrayInit(const RecordDecl *RD, const Expr *Init) { // FIXME: Csmith doesn't have pointer fields, I will // leave this function as future work } ReducePointerLevel::~ReducePointerLevel(void) { delete CollectionVisitor; delete RewriteVisitor; for (LevelToDeclMap::iterator I = AllPtrDecls.begin(), E = AllPtrDecls.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/ReducePointerLevel.h000066400000000000000000000076441402162750500210100ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REDUCE_POINTER_LEVEL_H #define REDUCE_POINTER_LEVEL_H #include #include "Transformation.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/DenseMap.h" namespace clang { class DeclGroupRef; class ASTContext; class Expr; class DeclaratorDecl; class RecordDecl; class FieldDecl; class VarDecl; class Type; class ArrayType; class RecordType; class InitListExpr; class ArraySubscriptExpr; class MemberExpr; class UnaryOperator; class DeclRefExpr; } class PointerLevelCollectionVisitor; class PointerLevelRewriteVisitor; class ReducePointerLevel : public Transformation { friend class PointerLevelCollectionVisitor; friend class PointerLevelRewriteVisitor; public: ReducePointerLevel(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), MaxIndirectLevel(0), TheDecl(NULL), TheRecordDecl(NULL) { } ~ReducePointerLevel(void); private: typedef llvm::SmallPtrSet DeclSet; typedef llvm::SmallPtrSet DeclRefExprSet; typedef llvm::SmallPtrSet MemberExprSet; typedef llvm::DenseMap LevelToDeclMap; typedef void (ReducePointerLevel::*InitListHandler)(const clang::Expr *Init, std::string &InitStr); typedef llvm::SmallVector IndexVector; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void getInitListExprString(const clang::InitListExpr *ILE, std::string &InitStr, InitListHandler Handler); const clang::DeclaratorDecl *getRefDecl(const clang::Expr *Exp); const clang::DeclRefExpr *getDeclRefExpr(const clang::Expr *Exp); const clang::DeclaratorDecl * getCanonicalDeclaratorDecl(const clang::Expr *E); void addOneDecl(const clang::DeclaratorDecl *DD, int IndirectLevel); void doAnalysis(void); void setRecordDecl(void); void copyInitStr(const clang::Expr *Exp, std::string &InitStr); void getNewLocalInitStr(const clang::Expr *Init, std::string &InitStr); void getNewGlobalInitStr(const clang::Expr *Init, std::string &InitStr); const clang::Expr *getFirstInitListElem(const clang::InitListExpr *E); void rewriteVarDecl(const clang::VarDecl *VD); void rewriteFieldDecl(const clang::FieldDecl *FD); void rewriteRecordInit(const clang::RecordDecl *RD, const clang::Expr *Init); void rewriteArrayInit(const clang::RecordDecl *RD, const clang::Expr *Init); void rewriteDerefOp(const clang::UnaryOperator *UO); void rewriteDeclRefExpr(const clang::DeclRefExpr *DRE); void replaceArrowWithDot(const clang::Expr *E); bool isPointerToSelf(const clang::Type *Ty, const clang::DeclaratorDecl *DD); void checkPrefixAndPostfix(const clang::UnaryOperator *UO); DeclSet VisitedDecls; DeclSet ValidDecls; DeclSet AddrTakenDecls; DeclRefExprSet VisitedDeclRefExprs; MemberExprSet VisitedMemberExprs; LevelToDeclMap AllPtrDecls; PointerLevelCollectionVisitor *CollectionVisitor; PointerLevelRewriteVisitor *RewriteVisitor; int MaxIndirectLevel; const clang::DeclaratorDecl *TheDecl; const clang::RecordDecl *TheRecordDecl ; // Unimplemented ReducePointerLevel(void); ReducePointerLevel(const ReducePointerLevel &); void operator=(const ReducePointerLevel &); }; #endif cvise-2.3.0/clang_delta/ReducePointerPairs.cpp000066400000000000000000000245551402162750500213520ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReducePointerPairs.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Reduce a pair of pointers at the same time if they have the following shape:\n\ int **p1;\n\ int ***p2 = &p1;\n\ and both p1 and p2 are not used anywhere except comparisons between \ p2 and &p1.\n"; static RegisterTransformation Trans("reduce-pointer-pairs", DescriptionMsg); class ReducePointerPairsCollectionVisitor : public RecursiveASTVisitor { public: explicit ReducePointerPairsCollectionVisitor(ReducePointerPairs *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitBinaryOperator(BinaryOperator *BO); private: ReducePointerPairs *ConsumerInstance; }; class ReducePointerPairsInvalidatingVisitor : public RecursiveASTVisitor { public: typedef SmallVector DeclRefExprQueue; explicit ReducePointerPairsInvalidatingVisitor(ReducePointerPairs *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitBinaryOperator(BinaryOperator *BO); private: void handleOneOperand(const Expr *E); ReducePointerPairs *ConsumerInstance; DeclRefExprQueue CurrentDeclRefExprs; DeclRefExprQueue CurrentPairedDeclRefExprs; }; bool ReducePointerPairsCollectionVisitor::VisitVarDecl(VarDecl *VD) { if (!ConsumerInstance->isValidVD(VD)) return true; const Expr *Init = VD->getAnyInitializer(); if (!Init) return true; ConsumerInstance->handleOnePair(VD->getCanonicalDecl(), Init->IgnoreParenCasts()); return true; } bool ReducePointerPairsCollectionVisitor::VisitBinaryOperator( BinaryOperator *BO) { if (BO->getOpcode() != BO_Assign) return true; const Expr *Lhs = BO->getLHS()->IgnoreParenCasts(); const VarDecl *VD = ConsumerInstance->getVarDeclFromDRE(Lhs); if (!VD || !ConsumerInstance->isValidVD(VD)) return true; ConsumerInstance->handleOnePair(VD, BO->getRHS()->IgnoreParenCasts()); return true; } bool ReducePointerPairsInvalidatingVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { const DeclRefExpr *CurrentDeclRefExpr = NULL; const DeclRefExpr *CurrentPairedDeclRefExpr = NULL; if (CurrentDeclRefExprs.size()) CurrentDeclRefExpr = CurrentDeclRefExprs.back(); if (CurrentPairedDeclRefExprs.size()) CurrentPairedDeclRefExpr = CurrentPairedDeclRefExprs.back(); if (DRE == CurrentDeclRefExpr) { CurrentDeclRefExprs.pop_back(); return true; } else if (DRE == CurrentPairedDeclRefExpr) { CurrentPairedDeclRefExprs.pop_back(); return true; } const VarDecl *VD = ConsumerInstance->getVarDeclFromDRE(DRE); if (VD) { ConsumerInstance->invalidateVarDecl(VD); ConsumerInstance->invalidatePairedVarDecl(VD); } return true; } bool ReducePointerPairsInvalidatingVisitor::VisitVarDecl(VarDecl *VD) { const VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (!ConsumerInstance->isMappedVarDecl(CanonicalVD)) return true; const Expr *Init = CanonicalVD->getAnyInitializer(); if (!Init) return true; if (ConsumerInstance->invalidatePairedVarDecl(CanonicalVD)) return true; const UnaryOperator *UO = dyn_cast(Init->IgnoreParenCasts()); if (!UO || (UO->getOpcode() != UO_AddrOf)) return true; const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); const VarDecl *PairedVD = ConsumerInstance->getVarDeclFromDRE(SubE); if (!PairedVD) return true; if (ConsumerInstance->ValidPointerPairs[CanonicalVD] == PairedVD) { const DeclRefExpr *DRE = dyn_cast(SubE); TransAssert(DRE && "Invalid DRE for Paired VarDecl!"); CurrentPairedDeclRefExprs.push_back(DRE); } return true; } void ReducePointerPairsInvalidatingVisitor::handleOneOperand(const Expr *E) { const VarDecl *VD = ConsumerInstance->getVarDeclFromDRE(E); if (VD && ConsumerInstance->isMappedVarDecl(VD)) { const DeclRefExpr *DRE = dyn_cast(E); TransAssert(DRE && "Invalid DeclRefExpr!"); CurrentDeclRefExprs.push_back(DRE); return; } if (const UnaryOperator *UO = dyn_cast(E)) { if (UO && (UO->getOpcode() == UO_AddrOf)) { const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); const VarDecl *PairedVD = ConsumerInstance->getVarDeclFromDRE(SubE); if (ConsumerInstance->isMappedVarDecl(PairedVD)) { const DeclRefExpr *DRE = dyn_cast(SubE); TransAssert(DRE && "Invalid DeclRefExpr with UnaryOperator!"); CurrentPairedDeclRefExprs.push_back(DRE); } } } } bool ReducePointerPairsInvalidatingVisitor::VisitBinaryOperator( BinaryOperator *BO) { if (BO->getOpcode() == BO_Assign) { const Expr *Lhs = BO->getLHS()->IgnoreParenCasts(); const VarDecl *VD = ConsumerInstance->getVarDeclFromDRE(Lhs); if (!VD) return true; const VarDecl *PairedVD = ConsumerInstance->ValidPointerPairs[VD]; if (!PairedVD) return true; const Expr *Rhs = BO->getRHS()->IgnoreParenCasts(); const UnaryOperator *UO = dyn_cast(Rhs); if (!UO || (UO->getOpcode() != UO_AddrOf)) { ConsumerInstance->ValidPointerPairs.erase(VD); return true; } const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); const VarDecl *RhsVD = ConsumerInstance->getVarDeclFromDRE(SubE); if (!RhsVD || (RhsVD != PairedVD)) ConsumerInstance->ValidPointerPairs.erase(VD); const DeclRefExpr *LhsDRE = dyn_cast(Lhs); TransAssert(LhsDRE && "Invalid LhsDRE!"); CurrentDeclRefExprs.push_back(LhsDRE); const DeclRefExpr *SubDRE = dyn_cast(SubE); TransAssert(SubDRE && "Invalid SubDRE!"); CurrentPairedDeclRefExprs.push_back(SubDRE); return true; } if (BO->isComparisonOp()) { handleOneOperand(BO->getLHS()->IgnoreParenCasts()); handleOneOperand(BO->getRHS()->IgnoreParenCasts()); } return true; } void ReducePointerPairs::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReducePointerPairsCollectionVisitor(this); InvalidatingVisitor = new ReducePointerPairsInvalidatingVisitor(this); } void ReducePointerPairs::HandleTranslationUnit(ASTContext &Ctx) { TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); TransAssert(InvalidatingVisitor && "NULL InvalidatingVisitor!"); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); InvalidatingVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheVarDecl && "NULL TheVarDecl!"); TransAssert(ThePairedVarDecl && "NULL ThePairedVarDecl!"); doRewriting(TheVarDecl); doRewriting(ThePairedVarDecl); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReducePointerPairs::doAnalysis(void) { for (PointerMap::iterator I = ValidPointerPairs.begin(), E = ValidPointerPairs.end(); I != E; ++I) { const VarDecl *PairedVD = (*I).second; if (!PairedVD) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) { TheVarDecl = (*I).first; ThePairedVarDecl = PairedVD; } } } void ReducePointerPairs::doRewriting(const VarDecl *VD) { const VarDecl *FirstVD = VD->getCanonicalDecl(); for(VarDecl::redecl_iterator RI = FirstVD->redecls_begin(), RE = FirstVD->redecls_end(); RI != RE; ++RI) { RewriteHelper->removeAStarBefore(*RI); } } bool ReducePointerPairs::isValidVD(const VarDecl *VD) { if (isInIncludedFile(VD) || dyn_cast(VD)) return false; const Type *Ty = VD->getType().getTypePtr(); if (!Ty->isPointerType()) return false; return true; } const VarDecl *ReducePointerPairs::getVarDeclFromDRE(const Expr *E) { TransAssert(E && "NULL Expr!"); const DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return NULL; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD || dyn_cast(VD)) return NULL; return VD->getCanonicalDecl(); } void ReducePointerPairs::handleOnePair(const VarDecl *VD, const Expr *E) { const UnaryOperator *UO = dyn_cast(E); if (!UO || (UO->getOpcode() != UO_AddrOf)) return; const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); const Type *Ty = SubE->getType().getTypePtr(); if (!Ty->isPointerType()) return; const VarDecl *PairedVD = getVarDeclFromDRE(SubE); if (PairedVD && !ValidPointerPairs[VD]) { ValidPointerPairs[VD] = PairedVD; } } bool ReducePointerPairs::isMappedVarDecl(const VarDecl *VD) { if (!VD) return false; for (PointerMap::iterator I = ValidPointerPairs.begin(), E = ValidPointerPairs.end(); I != E; ++I) { if ((VD == (*I).first) || (VD == (*I).second)) return true; } return false; } void ReducePointerPairs::invalidateVarDecl(const VarDecl *VD) { PointerMap::iterator I = ValidPointerPairs.begin(); PointerMap::iterator E = ValidPointerPairs.end(); for (; I != E; ++I) { const VarDecl *D = (*I).first; if (VD == D) ValidPointerPairs[D] = NULL; } } bool ReducePointerPairs::invalidatePairedVarDecl(const VarDecl *VD) { bool RV = false; PointerMap::iterator I = ValidPointerPairs.begin(); PointerMap::iterator E = ValidPointerPairs.end(); for (; I != E; ++I) { const VarDecl *D = (*I).first; if (VD == (*I).second) { ValidPointerPairs[D] = NULL; RV = true; } } return RV; } ReducePointerPairs::~ReducePointerPairs(void) { delete CollectionVisitor; delete InvalidatingVisitor; } cvise-2.3.0/clang_delta/ReducePointerPairs.h000066400000000000000000000040741402162750500210110ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REDUCE_POINTER_PAIRS_H #define REDUCE_POINTER_PAIRS_H #include "Transformation.h" #include "llvm/ADT/DenseMap.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; } class ReducePointerPairsCollectionVisitor; class ReducePointerPairsInvalidatingVisitor; class ReducePointerPairs : public Transformation { friend class ReducePointerPairsCollectionVisitor; friend class ReducePointerPairsInvalidatingVisitor; public: ReducePointerPairs(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), InvalidatingVisitor(NULL), TheVarDecl(NULL), ThePairedVarDecl(NULL) { } ~ReducePointerPairs(void); private: typedef llvm::DenseMap PointerMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOnePair(const clang::VarDecl *VD, const clang::Expr *E); bool isValidVD(const clang::VarDecl *VD); bool invalidatePairedVarDecl(const clang::VarDecl *VD); const clang::VarDecl *getVarDeclFromDRE(const clang::Expr *E); bool isMappedVarDecl(const clang::VarDecl *VD); void doRewriting(const clang::VarDecl *VD); void doAnalysis(void); void invalidateVarDecl(const clang::VarDecl *VD); PointerMap ValidPointerPairs; ReducePointerPairsCollectionVisitor *CollectionVisitor; ReducePointerPairsInvalidatingVisitor *InvalidatingVisitor; const clang::VarDecl *TheVarDecl; const clang::VarDecl *ThePairedVarDecl; // Unimplemented ReducePointerPairs(void); ReducePointerPairs(const ReducePointerPairs &); void operator=(const ReducePointerPairs &); }; #endif cvise-2.3.0/clang_delta/RemoveAddrTaken.cpp000066400000000000000000000113551402162750500206100ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveAddrTaken.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove an addr-taken operator if \n\ * the subexpr is type of pointer, or \n\ * the subexpr is type of integer and the addr-taken operator is \ an operand of a comparison operator, or \n\ * the entire addr-taken expr is an argument of a function, \ and the argument doesn't have a correponding parameter in function's \ declaration.\n"; static RegisterTransformation Trans("remove-addr-taken", DescriptionMsg); class RemoveAddrTakenCollectionVisitor : public RecursiveASTVisitor { public: explicit RemoveAddrTakenCollectionVisitor(RemoveAddrTaken *Instance) : ConsumerInstance(Instance) { } bool VisitUnaryOperator(UnaryOperator *UO); bool VisitBinaryOperator(BinaryOperator *BO); bool VisitCallExpr(CallExpr *CE); private: void handleOneAddrTakenOp(const UnaryOperator *UO); void handleOneOperand(const Expr *E); RemoveAddrTaken *ConsumerInstance; }; void RemoveAddrTakenCollectionVisitor::handleOneAddrTakenOp( const UnaryOperator *UO) { if (ConsumerInstance->isInIncludedFile(UO) || ConsumerInstance->VisitedAddrTakenOps.count(UO)) return; ConsumerInstance->VisitedAddrTakenOps.insert(UO); ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->TransformationCounter == ConsumerInstance->ValidInstanceNum) ConsumerInstance->TheUO = UO; } bool RemoveAddrTakenCollectionVisitor::VisitUnaryOperator(UnaryOperator *UO) { if (UO->getOpcode() != UO_AddrOf) return true; const Expr *E = UO->getSubExpr(); const Type *Ty = E->getType().getTypePtr(); if (!Ty->isPointerType()) return true; handleOneAddrTakenOp(UO); return true; } void RemoveAddrTakenCollectionVisitor::handleOneOperand(const Expr *E) { const UnaryOperator *UO = dyn_cast(E); if (!UO) return; if (UO->getOpcode() != UO_AddrOf) return; const Expr *SubE = UO->getSubExpr(); const Type *Ty = SubE->getType().getTypePtr(); if (!Ty->isIntegerType()) return; handleOneAddrTakenOp(UO); } bool RemoveAddrTakenCollectionVisitor::VisitBinaryOperator(BinaryOperator *BO) { if (!BO->isComparisonOp()) return true; handleOneOperand(BO->getLHS()); handleOneOperand(BO->getRHS()); return true; } // handle special cases like // void f1(); // void f2(void) { // f1(xxx); // } bool RemoveAddrTakenCollectionVisitor::VisitCallExpr(CallExpr *CE) { const FunctionDecl *FD = CE->getDirectCallee(); if (!FD) return true; unsigned NumParams = FD->getNumParams(); if (NumParams != 0) return true; for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { const Expr *Arg = *I; const UnaryOperator *UO = dyn_cast(Arg); if (!UO || (UO->getOpcode() != UO_AddrOf)) continue; handleOneAddrTakenOp(UO); } return true; } void RemoveAddrTaken::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveAddrTakenCollectionVisitor(this); } bool RemoveAddrTaken::HandleTopLevelDecl(DeclGroupRef D) { TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); if (TransformationManager::isCXXLangOpt()) { ValidInstanceNum = 0; return true; } for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { FunctionDecl *FD = dyn_cast(*I); if (!FD || !FD->isThisDeclarationADefinition()) continue; CollectionVisitor->TraverseDecl(*I); } return true; } void RemoveAddrTaken::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheUO && "NULL UnaryOperator!"); rewriteAddrTakenOp(TheUO); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveAddrTaken::rewriteAddrTakenOp(const UnaryOperator *UO) { SourceLocation Loc = UO->getOperatorLoc(); TheRewriter.RemoveText(Loc, 1); } RemoveAddrTaken::~RemoveAddrTaken(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/RemoveAddrTaken.h000066400000000000000000000027131402162750500202530ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_ADDR_TAKEN_H #define REMOVE_ADDR_TAKEN_H #include "Transformation.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; class UnaryOperator; } class RemoveAddrTakenCollectionVisitor; class RemoveAddrTaken : public Transformation { friend class RemoveAddrTakenCollectionVisitor; public: RemoveAddrTaken(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL) { } ~RemoveAddrTaken(void); private: typedef llvm::SmallPtrSet UnaryOperatorSet; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void rewriteAddrTakenOp(const clang::UnaryOperator *UO); UnaryOperatorSet VisitedAddrTakenOps; RemoveAddrTakenCollectionVisitor *CollectionVisitor; const clang::UnaryOperator *TheUO; // Unimplemented RemoveAddrTaken(void); RemoveAddrTaken(const RemoveAddrTaken &); void operator=(const RemoveAddrTaken &); }; #endif cvise-2.3.0/clang_delta/RemoveArray.cpp000066400000000000000000000177641402162750500200430ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2017, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveArray.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Change an array var to a corresponding non-array one. \ For example, replace \"int a[10];\" with \"int a;\". Conditions \n\ * Array dimension is 1, and \n\ * array var is not referenced except via ArraySubscriptExpr. \n\ All relevant ArraySubscriptExpr[s] will be rewritten accordingly. \n"; static RegisterTransformation Trans("remove-array", DescriptionMsg); typedef llvm::SmallPtrSet ArraySubscriptExprSet; class InvalidArraySubscriptExprVisitor : public RecursiveASTVisitor { public: InvalidArraySubscriptExprVisitor(RemoveArray *Instance, const VarDecl *VD, ArraySubscriptExprSet &ES) : ConsumerInstance(Instance), TheVarDecl(VD), InvalidExprs(ES) { } bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); private: RemoveArray *ConsumerInstance; const VarDecl *TheVarDecl; ArraySubscriptExprSet &InvalidExprs; }; bool InvalidArraySubscriptExprVisitor::VisitArraySubscriptExpr( ArraySubscriptExpr *ASE) { const VarDecl *VD = ConsumerInstance->getVarDeclFromArraySubscriptExpr(ASE); if (VD == TheVarDecl) InvalidExprs.insert(ASE); return true; } class RemoveArrayCollectionVisitor : public RecursiveASTVisitor { public: explicit RemoveArrayCollectionVisitor(RemoveArray *Instance) : ConsumerInstance(Instance), CurrDeclRefExpr(NULL) { } bool VisitVarDecl(VarDecl *VD); bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); bool VisitDeclRefExpr(DeclRefExpr *DRE); private: RemoveArray *ConsumerInstance; const DeclRefExpr *CurrDeclRefExpr; }; bool RemoveArrayCollectionVisitor::VisitVarDecl(VarDecl *VD) { ConsumerInstance->handleOneVarDecl(VD); return true; } bool RemoveArrayCollectionVisitor::VisitArraySubscriptExpr( ArraySubscriptExpr *ASE) { // we only have one-dimension array, so we are safe here. const Expr *BaseE = ASE->getBase()->IgnoreParenCasts(); TransAssert(BaseE && "Empty Base expression!"); const DeclRefExpr *DRE = dyn_cast(BaseE); if (!DRE) return true; CurrDeclRefExpr = DRE; ConsumerInstance->addOneArraySubscriptExpr(ASE, DRE); return true; } bool RemoveArrayCollectionVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { if (CurrDeclRefExpr != DRE) ConsumerInstance->deleteOneVarDecl(DRE); CurrDeclRefExpr = NULL; return true; } void RemoveArray::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveArrayCollectionVisitor(this); } void RemoveArray::HandleTranslationUnit(ASTContext &Ctx) { TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheArrayVarDecl && "NULL TheArrayVarDecl!"); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveArray::doAnalysis(void) { for (VarDeclToArraySubscriptExprMap::iterator I = ValidVarToASEMap.begin(), E = ValidVarToASEMap.end(); I != E; ++I) { if (!((*I).second)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) { TheArrayVarDecl = (*I).first; TheASEVec = (*I).second; } } } const VarDecl * RemoveArray::getVarDeclFromArraySubscriptExpr(const ArraySubscriptExpr *ASE) { const Expr *BaseE = ASE->getBase()->IgnoreParenCasts(); TransAssert(BaseE && "Empty Base expression!"); const DeclRefExpr *DRE = dyn_cast(BaseE); if (!DRE) return NULL; const VarDecl *VD = dyn_cast(DRE->getDecl()); if (!VD) return NULL; return VD->getCanonicalDecl(); } void RemoveArray::getBracketLocPair(const VarDecl *VD, BracketLocPair &LocPair) { SourceLocation StartLoc = VD->getLocation(); SourceLocation BPStartLoc, BPEndLoc; BPStartLoc = RewriteHelper->getLocationUntil(StartLoc, '['); BPEndLoc = RewriteHelper->getLocationUntil(BPStartLoc, ']'); LocPair.first = BPStartLoc; LocPair.second = BPEndLoc; } void RemoveArray::doRewriting(void) { // rewrite decls first const VarDecl *FirstVD = TheArrayVarDecl->getCanonicalDecl(); for(VarDecl::redecl_iterator RI = FirstVD->redecls_begin(), RE = FirstVD->redecls_end(); RI != RE; ++RI) { BracketLocPair LocPair; getBracketLocPair((*RI), LocPair); TheRewriter.RemoveText(SourceRange(LocPair.first, LocPair.second)); } // Then rewrite ArraySubscriptExprs if (!TheASEVec) return; // filter out inner subscript that refers to the same var as the outer // expr, e.g.: // x[x[0]] // we don't need to rewrite x[0] in this case ArraySubscriptExprSet InvalidExprs; for (ArraySubscriptExprVector::iterator I = TheASEVec->begin(), E = TheASEVec->end(); I != E; ++I) { ArraySubscriptExpr *ASE = (*I); if (InvalidExprs.count(ASE)) continue; Expr *IdxE = ASE->getIdx(); if (!IdxE) continue; const VarDecl *VD = getVarDeclFromArraySubscriptExpr(ASE); TransAssert(VD && "NULL VarDecl from ArraySubscriptExpr!"); InvalidArraySubscriptExprVisitor V(this, VD, InvalidExprs); V.TraverseStmt(IdxE); } for (ArraySubscriptExprVector::iterator I = TheASEVec->begin(), E = TheASEVec->end(); I != E; ++I) { if (InvalidExprs.count(*I)) continue; const Expr *IdxE = (*I)->getIdx(); RewriteHelper->removeArraySubscriptExpr(IdxE); } } void RemoveArray::deleteOneVarDecl(const DeclRefExpr *DRE) { const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); ArraySubscriptExprVector *ASEVec = ValidVarToASEMap[CanonicalVD]; if (ASEVec) { delete ASEVec; ValidVarToASEMap[CanonicalVD] = NULL; } } void RemoveArray::addOneArraySubscriptExpr(ArraySubscriptExpr *ASE, const DeclRefExpr *DRE) { const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); ArraySubscriptExprVector *ASEVec = ValidVarToASEMap[CanonicalVD]; if (ASEVec) ASEVec->push_back(ASE); } void RemoveArray::handleOneVarDecl(const VarDecl *VD) { if (isInIncludedFile(VD) || VD->getAnyInitializer()) return; const Type *Ty = VD->getType().getTypePtr(); const ArrayType *ArrayTy = dyn_cast(Ty); if (!ArrayTy) return; unsigned Dim = getArrayDimension(ArrayTy); if (Dim != 1) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); ArraySubscriptExprVector *ASEVec = ValidVarToASEMap[CanonicalVD]; if (ASEVec) return; ASEVec = new ArraySubscriptExprVector(); ValidVarToASEMap[CanonicalVD] = ASEVec; } RemoveArray::~RemoveArray(void) { delete CollectionVisitor; for (VarDeclToArraySubscriptExprMap::iterator I = ValidVarToASEMap.begin(), E = ValidVarToASEMap.end(); I != E; ++I) { ArraySubscriptExprVector *ASEVec = (*I).second; delete ASEVec; } } cvise-2.3.0/clang_delta/RemoveArray.h000066400000000000000000000044021402162750500174710ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_ARRAY_H #define REMOVE_ARRAY_H #include #include "Transformation.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; class DeclRefExpr; } class RemoveArrayCollectionVisitor; class InvalidArraySubscriptExprVisitor; class RemoveArray : public Transformation { friend class RemoveArrayCollectionVisitor; friend class InvalidArraySubscriptExprVisitor; public: RemoveArray(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheArrayVarDecl(NULL), TheASEVec(NULL) { } ~RemoveArray(void); private: typedef llvm::SmallVector ArraySubscriptExprVector; typedef llvm::MapVector VarDeclToArraySubscriptExprMap; typedef std::pair BracketLocPair; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doAnalysis(void); void doRewriting(void); void addOneArraySubscriptExpr(clang::ArraySubscriptExpr *ASE, const clang::DeclRefExpr *DRE); void deleteOneVarDecl(const clang::DeclRefExpr *DRE); void handleOneVarDecl(const clang::VarDecl *VD); void getBracketLocPair(const clang::VarDecl *VD, BracketLocPair &LocPair); const clang::VarDecl *getVarDeclFromArraySubscriptExpr( const clang::ArraySubscriptExpr *ASE); VarDeclToArraySubscriptExprMap ValidVarToASEMap; RemoveArrayCollectionVisitor *CollectionVisitor; const clang::VarDecl *TheArrayVarDecl; ArraySubscriptExprVector *TheASEVec; // Unimplemented RemoveArray(void); RemoveArray(const RemoveArray &); void operator=(const RemoveArray &); }; #endif cvise-2.3.0/clang_delta/RemoveBaseClass.cpp000066400000000000000000000230071402162750500206100ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveBaseClass.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "CommonRenameClassRewriteVisitor.h" #include "TransformationManager.h" using namespace clang; using namespace clang_delta_common_visitor; static const char *DescriptionMsg = "This pass removes a base class from its class hierarchy if \n\ * it has less than or equal to 5 declarations, and \n\ * it is not a templated class. \n\ All its declarations will be moved into one of its subclasses, \ and all references to this base class will be replaced with \ the corresponding subclass. \n"; // Note that this pass doesn't do much analysis, so // it will produce quite a few incompilable code, especially // when multi-inheritance is involved. static RegisterTransformation Trans("remove-base-class", DescriptionMsg); class RemoveBaseClassBaseVisitor : public RecursiveASTVisitor { public: explicit RemoveBaseClassBaseVisitor( RemoveBaseClass *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: RemoveBaseClass *ConsumerInstance; }; bool RemoveBaseClassBaseVisitor::VisitCXXRecordDecl( CXXRecordDecl *CXXRD) { ConsumerInstance->handleOneCXXRecordDecl(CXXRD); return true; } class RemoveBaseClassRewriteVisitor : public CommonRenameClassRewriteVisitor { public: RemoveBaseClassRewriteVisitor(Transformation *Instance, Rewriter *RT, RewriteUtils *Helper, const CXXRecordDecl *CXXRD, const std::string &Name) : CommonRenameClassRewriteVisitor (Instance, RT, Helper, CXXRD, Name) { } }; void RemoveBaseClass::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveBaseClassBaseVisitor(this); } void RemoveBaseClass::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheBaseClass && "TheBaseClass is NULL!"); TransAssert(TheDerivedClass && "TheDerivedClass is NULL!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RewriteVisitor = new RemoveBaseClassRewriteVisitor(this, &TheRewriter, RewriteHelper, TheBaseClass->getCanonicalDecl(), TheDerivedClass->getNameAsString()); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doRewrite(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool RemoveBaseClass::isDirectlyDerivedFrom(const CXXRecordDecl *SubC, const CXXRecordDecl *Base) { for (CXXRecordDecl::base_class_const_iterator I = SubC->bases_begin(), E = SubC->bases_end(); I != E; ++I) { if (I->getType()->isDependentType()) continue; const CXXRecordDecl *BaseDecl = dyn_cast(I->getType()->getAs()->getDecl()); if (Base->getCanonicalDecl() == BaseDecl->getCanonicalDecl()) return true; } return false; } void RemoveBaseClass::handleOneCXXRecordDecl(const CXXRecordDecl *CXXRD) { if (isSpecialRecordDecl(CXXRD) || CXXRD->getDescribedClassTemplate() || !CXXRD->hasDefinition()) return; const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (VisitedCXXRecordDecls.count(CanonicalRD)) return; VisitedCXXRecordDecls.insert(CanonicalRD); if (CanonicalRD->getNumBases()) { const CXXRecordDecl *Base = NULL; for (CXXRecordDeclSet::iterator I = AllBaseClasses.begin(), E = AllBaseClasses.end(); I != E; ++I) { if (const ClassTemplateSpecializationDecl * CTSD = dyn_cast (CanonicalRD->getDefinition())) { if (!CTSD->isExplicitSpecialization()) continue; } if (isInIncludedFile(*I)) continue; if (isDirectlyDerivedFrom(CanonicalRD, *I)) { Base = (*I); ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TransAssert(Base->hasDefinition() && "Base class does not have any definition!"); TheBaseClass = Base->getDefinition(); TransAssert(CanonicalRD->hasDefinition() && "Derived class does not have any definition!"); TheDerivedClass = CanonicalRD->getDefinition(); } } } return; } if (getNumExplicitDecls(CanonicalRD) > MaxNumDecls) return; if (!AllBaseClasses.count(CanonicalRD)) AllBaseClasses.insert(CanonicalRD); } void RemoveBaseClass::doRewrite(void) { copyBaseClassDecls(); removeBaseSpecifier(); RewriteHelper->removeClassDecls(TheBaseClass); // ISSUE: I didn't handle Base initializer in a Ctor's initlist. // * keeping it untouched is wrong, because delegating constructors // are only valie in c++11 // * naively removing the base initializer doesn't work in some cases, // e.g., // class A { // A(A&) {} // A &a; // }; // class C : A { // C(A &x) : A(x) {} // }; // during transformation, removing A(x) will leave &a un-initialized. // I chose to simply delete the base initializer. Seemingly we will // generate fewer incompilable code by doing so... removeBaseInitializer(); } // ISSUE: directly copying decls could bring in name conflicts void RemoveBaseClass::copyBaseClassDecls(void) { if (!getNumExplicitDecls(TheBaseClass)) return; SourceLocation StartLoc = TheBaseClass->getBraceRange().getBegin(); SourceLocation EndLoc = TheBaseClass->getBraceRange().getEnd(); TransAssert(EndLoc.isValid() && "Invalid RBraceLoc!"); EndLoc = EndLoc.getLocWithOffset(-1); std::string DeclsStr = TheRewriter.getRewrittenText(SourceRange(StartLoc, EndLoc)); TransAssert(!DeclsStr.empty() && "Empty DeclsStr!"); SourceLocation InsertLoc = TheDerivedClass->getBraceRange().getEnd(); TheRewriter.InsertTextBefore(InsertLoc, DeclsStr); } bool RemoveBaseClass::isTheBaseClass(const CXXBaseSpecifier &Specifier) { const Type *Ty = TheBaseClass->getTypeForDecl(); return Context->hasSameType(Specifier.getType(), Ty->getCanonicalTypeInternal()); } void RemoveBaseClass::removeBaseSpecifier(void) { unsigned NumBases = TheDerivedClass->getNumBases(); TransAssert((NumBases >= 1) && "TheDerivedClass doesn't have any base!"); if (NumBases == 1) { SourceLocation StartLoc = TheDerivedClass->getLocation(); StartLoc = RewriteHelper->getLocationUntil(StartLoc, ':'); SourceLocation EndLoc = RewriteHelper->getLocationUntil(StartLoc, '{'); EndLoc = EndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); return; } CXXRecordDecl::base_class_const_iterator I = TheDerivedClass->bases_begin(); // remove 'Y,' in code like 'class X : public Y, Z {};' if (isTheBaseClass(*I)) { RewriteHelper->removeTextUntil((*I).getSourceRange(), ','); return; } ++I; CXXRecordDecl::base_class_const_iterator E = TheDerivedClass->bases_end(); for (; I != E; ++I) { if (isTheBaseClass(*I)) { // remove ',Z' in code like 'class X : public Y, Z {};' SourceRange Range = (*I).getSourceRange(); SourceLocation EndLoc = RewriteHelper->getEndLocationFromBegin(Range); RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc); return; } } TransAssert(0 && "Unreachable code!"); } void RemoveBaseClass::rewriteOneCtor(const CXXConstructorDecl *Ctor) { unsigned Idx = 0; const CXXCtorInitializer *Init = NULL; for (CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(), E = Ctor->init_end(); I != E; ++I) { if (!(*I)->isWritten()) continue; if ((*I)->isBaseInitializer()) { const Type *Ty = (*I)->getBaseClass(); TransAssert(Ty && "Invalid Base Class Type!"); if (Context->hasSameType(Ty->getCanonicalTypeInternal(), TheBaseClass->getTypeForDecl()->getCanonicalTypeInternal())) { Init = (*I); break; } } Idx++; } if (Init) { RewriteHelper->removeCXXCtorInitializer(Init, Idx, getNumCtorWrittenInitializers(*Ctor)); } } void RemoveBaseClass::removeBaseInitializer(void) { for (CXXRecordDecl::ctor_iterator I = TheDerivedClass->ctor_begin(), E = TheDerivedClass->ctor_end(); I != E; ++I) { if ((*I)->isThisDeclarationADefinition() && !(*I)->isDefaulted()) rewriteOneCtor(*I); } } RemoveBaseClass::~RemoveBaseClass(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/RemoveBaseClass.h000066400000000000000000000041521402162750500202550ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_BASE_CLASS_H #define REMOVE_BASE_CLASS_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXBaseSpecifier; class CXXConstructorDecl; } class RemoveBaseClassBaseVisitor; class RemoveBaseClassRewriteVisitor; class RemoveBaseClass : public Transformation { friend class RemoveBaseClassBaseVisitor; public: RemoveBaseClass(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheBaseClass(NULL), TheDerivedClass(NULL), MaxNumDecls(5) { } ~RemoveBaseClass(void); private: typedef llvm::SmallPtrSet CXXRecordDeclSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneCXXRecordDecl(const clang::CXXRecordDecl *CXXRD); void copyBaseClassDecls(void); void removeBaseSpecifier(void); void removeBaseInitializer(void); void rewriteOneCtor(const clang::CXXConstructorDecl *Ctor); bool isDirectlyDerivedFrom(const clang::CXXRecordDecl *SubC, const clang::CXXRecordDecl *Base); void doRewrite(void); bool isTheBaseClass(const clang::CXXBaseSpecifier &Specifier); CXXRecordDeclSet VisitedCXXRecordDecls; CXXRecordDeclSet AllBaseClasses; RemoveBaseClassBaseVisitor *CollectionVisitor; RemoveBaseClassRewriteVisitor *RewriteVisitor; const clang::CXXRecordDecl *TheBaseClass; const clang::CXXRecordDecl *TheDerivedClass; const unsigned MaxNumDecls; // Unimplemented RemoveBaseClass(void); RemoveBaseClass(const RemoveBaseClass &); void operator=(const RemoveBaseClass &); }; #endif cvise-2.3.0/clang_delta/RemoveCtorInitializer.cpp000066400000000000000000000077031402162750500220700ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveCtorInitializer.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass tries to remove an initializer from a Ctor. \n"; static RegisterTransformation Trans("remove-ctor-initializer", DescriptionMsg); class RemoveCtorInitializerASTVisitor : public RecursiveASTVisitor { public: explicit RemoveCtorInitializerASTVisitor( RemoveCtorInitializer *Instance) : ConsumerInstance(Instance) { } bool VisitCXXConstructorDecl(CXXConstructorDecl *Ctor); private: RemoveCtorInitializer *ConsumerInstance; }; bool RemoveCtorInitializerASTVisitor::VisitCXXConstructorDecl( CXXConstructorDecl *Ctor) { if (ConsumerInstance->isInIncludedFile(Ctor)) return true; unsigned Idx = 0; for (CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(), E = Ctor->init_end(); I != E; ++I) { const CXXCtorInitializer *Init = (*I); if (!Init->isWritten()) { continue; } if (Init->isInClassMemberInitializer() || Init->isPackExpansion() || Init->isDelegatingInitializer()) { Idx++; continue; } if (const FieldDecl *Field = Init->getAnyMember()) { const Type *Ty = Field->getType().getTypePtr(); if (!ConsumerInstance->isValidType(Ty)) { Idx++; continue; } } else if (const Type *Ty = Init->getBaseClass()) { const CXXRecordDecl *Base = ConsumerInstance->getBaseDeclFromType(Ty); if (Base && Base->hasDefinition() && Base->needsImplicitDefaultConstructor()) { Idx++; continue; } } ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheInitializer = Init; ConsumerInstance->TheCtorDecl = Ctor; ConsumerInstance->TheIndex = Idx; } Idx++; } return true; } void RemoveCtorInitializer::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveCtorInitializerASTVisitor(this); } void RemoveCtorInitializer::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheCtorDecl && "TheCtorDecl is NULL!"); TransAssert(TheInitializer && "TheInitializer is NULL!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RewriteHelper->removeCXXCtorInitializer(TheInitializer, TheIndex, getNumCtorWrittenInitializers(*TheCtorDecl)); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool RemoveCtorInitializer::isValidType(const Type *Ty) { if (Ty->isReferenceType()) return false; if (const RecordType *RTy = Ty->getAs()) { const CXXRecordDecl *CXXRD = dyn_cast(RTy->getDecl()); if (!CXXRD) return true; return !CXXRD->needsImplicitDefaultConstructor(); } return true; } RemoveCtorInitializer::~RemoveCtorInitializer(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/RemoveCtorInitializer.h000066400000000000000000000027261402162750500215350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_CTOR_INITIALIZER_H #define REMOVE_CTOR_INITIALIZER_H #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXConstructorDecl; class CXXCtorInitializer; } class RemoveCtorInitializerASTVisitor; class RemoveCtorInitializer : public Transformation { friend class RemoveCtorInitializerASTVisitor; public: RemoveCtorInitializer(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheCtorDecl(NULL), TheInitializer(NULL), TheIndex(0) { } ~RemoveCtorInitializer(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isValidType(const clang::Type *Ty); RemoveCtorInitializerASTVisitor *CollectionVisitor; const clang::CXXConstructorDecl *TheCtorDecl; const clang::CXXCtorInitializer *TheInitializer; unsigned TheIndex; // Unimplemented RemoveCtorInitializer(void); RemoveCtorInitializer(const RemoveCtorInitializer &); void operator=(const RemoveCtorInitializer &); }; #endif cvise-2.3.0/clang_delta/RemoveEnumMemberValue.cpp000066400000000000000000000062131402162750500220010ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2019 The University of Utah // Copyright (c) 2012 Konstantin Tokarev // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveEnumMemberValue.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove enum member value. \n"; static RegisterTransformation Trans("remove-enum-member-value", DescriptionMsg); class RemoveEnumMemberValueAnalysisVisitor : public RecursiveASTVisitor { public: explicit RemoveEnumMemberValueAnalysisVisitor(RemoveEnumMemberValue *Instance) : ConsumerInstance(Instance) { } bool VisitEnumConstantDecl(EnumConstantDecl *ECD); private: RemoveEnumMemberValue *ConsumerInstance; }; bool RemoveEnumMemberValueAnalysisVisitor::VisitEnumConstantDecl( EnumConstantDecl *ECD) { if (ConsumerInstance->isInIncludedFile(ECD) || !ECD->getInitExpr()) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheEnumConstantDecl = ECD; } return true; } void RemoveEnumMemberValue::Initialize(ASTContext &context) { Transformation::Initialize(context); AnalysisVisitor = new RemoveEnumMemberValueAnalysisVisitor(this); } void RemoveEnumMemberValue::HandleTranslationUnit(ASTContext &Ctx) { AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheEnumConstantDecl && "NULL TheEnumConstantDecl!"); removeEnumValue(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } static int getOffset(const char *Buf, char Symbol) { int Offset = 0; while (*Buf != Symbol) { Buf--; if (*Buf == '\0') break; Offset--; } return Offset; } void RemoveEnumMemberValue::removeEnumValue() { SourceManager &SrcManager = TheRewriter.getSourceMgr(); SourceRange Range = TheEnumConstantDecl->getInitExpr()->getSourceRange(); SourceLocation StartLoc = Range.getBegin(); if (StartLoc.isMacroID()) { Range = SrcManager.getExpansionRange(StartLoc).getAsRange(); StartLoc = SrcManager.getExpansionLoc(StartLoc); } const char *Buf = SrcManager.getCharacterData(StartLoc); int offset = getOffset(Buf, '='); Range.setBegin(StartLoc.getLocWithOffset(offset)); TheRewriter.RemoveText(Range); } RemoveEnumMemberValue::~RemoveEnumMemberValue() { delete AnalysisVisitor; } cvise-2.3.0/clang_delta/RemoveEnumMemberValue.h000066400000000000000000000026011402162750500214430ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2018 The University of Utah // Copyright (c) 2012 Konstantin Tokarev // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNUSED_MEMBER_VALUE_H #define REMOVE_UNUSED_MEMBER_VALUE_H #include #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class EnumConstantDecl; } class RemoveEnumMemberValueAnalysisVisitor; class RemoveEnumMemberValue : public Transformation { friend class RemoveEnumMemberValueAnalysisVisitor; public: RemoveEnumMemberValue(const char *TransName, const char *Desc) : Transformation(TransName, Desc), AnalysisVisitor(0), TheEnumConstantDecl(0) { } ~RemoveEnumMemberValue(); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void removeEnumValue(); RemoveEnumMemberValueAnalysisVisitor *AnalysisVisitor; clang::EnumConstantDecl *TheEnumConstantDecl; // Unimplemented RemoveEnumMemberValue(); RemoveEnumMemberValue(const RemoveEnumMemberValue &); void operator=(const RemoveEnumMemberValue &); }; #endif cvise-2.3.0/clang_delta/RemoveNamespace.cpp000066400000000000000000001105241402162750500206450ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveNamespace.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove namespaces. This pass tries to remove namespace without \ introducing name conflicts. \n"; static RegisterTransformation Trans("remove-namespace", DescriptionMsg); class RemoveNamespaceASTVisitor : public RecursiveASTVisitor { public: explicit RemoveNamespaceASTVisitor(RemoveNamespace *Instance) : ConsumerInstance(Instance) { } bool VisitNamespaceDecl(NamespaceDecl *ND); private: RemoveNamespace *ConsumerInstance; }; // A visitor for rewriting decls in the namespace being removed // ISSUE: quite a lot of functionality could be provided by the // RenameClassRewriteVisitor from RenameClass.cpp. // I have certain hesitation of factoring out // RenameClassRewriteVisitor for common uses. // A couple of reasons: // * RenameClassRewriteVisitor is only suitable for renaming // classes, but here we will be facing more types, e.g., enum. // * RenameClassRewriteVisitor handles one class, but here // we need to rename multiple conflicting classes; // * some processing logic is different here // * I don't want to make two transformations interference with // each other // Therefore, we will have some code duplications (but not much // since I put quite a few common utility functions into RewriteUtils) class RemoveNamespaceRewriteVisitor : public RecursiveASTVisitor { public: explicit RemoveNamespaceRewriteVisitor(RemoveNamespace *Instance) : ConsumerInstance(Instance), SkipRewriteName(false), SkipTraverseNestedNameSpecifier(false) { } bool VisitNamespaceDecl(NamespaceDecl *ND); bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); bool VisitUsingDecl(UsingDecl *D); bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); bool VisitCXXConstructorDecl(CXXConstructorDecl *CtorDecl); bool VisitCXXDestructorDecl(CXXDestructorDecl *DtorDecl); bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitRecordTypeLoc(RecordTypeLoc RTLoc); bool VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TSPLoc); bool VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); bool VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc DTSLoc); bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TyLoc); bool VisitTypedefTypeLoc(TypedefTypeLoc TyLoc); bool VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *TSD); bool VisitEnumTypeLoc(EnumTypeLoc TpLoc); bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc SpecifierLoc); private: RemoveNamespace *ConsumerInstance; bool SkipRewriteName; bool SkipTraverseNestedNameSpecifier; }; bool RemoveNamespaceASTVisitor::VisitNamespaceDecl(NamespaceDecl *ND) { ConsumerInstance->handleOneNamespaceDecl(ND); return true; } // ISSUE: I am not sure why, but RecursiveASTVisitor doesn't recursively // visit base classes from explicit template specialization, e.g., // struct A { }; // template class B : public A { }; // template<> class B : public A { }; // In the above case, A won't be touched. // So we have to do it manually bool RemoveNamespaceRewriteVisitor::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *TSD) { if (!TSD->isExplicitSpecialization() || !TSD->isCompleteDefinition()) return true; for (CXXRecordDecl::base_class_const_iterator I = TSD->bases_begin(), E = TSD->bases_end(); I != E; ++I) { TypeSourceInfo *TSI = (*I).getTypeSourceInfo(); TransAssert(TSI && "Bad TypeSourceInfo!"); TraverseTypeLoc(TSI->getTypeLoc()); } return true; } bool RemoveNamespaceRewriteVisitor::VisitNamespaceDecl(NamespaceDecl *ND) { if (ConsumerInstance->isForUsingNamedDecls) return true; const NamespaceDecl *CanonicalND = ND->getCanonicalDecl(); if (CanonicalND != ConsumerInstance->TheNamespaceDecl) return true; ConsumerInstance->removeNamespace(ND); return true; } bool RemoveNamespaceRewriteVisitor::VisitUsingDirectiveDecl( UsingDirectiveDecl *D) { if (ConsumerInstance->isForUsingNamedDecls) return true; if (ConsumerInstance->UselessUsingDirectiveDecls.count(D)) { ConsumerInstance->RewriteHelper->removeDecl(D); return true; } const NamespaceDecl *CanonicalND = D->getNominatedNamespace()->getCanonicalDecl(); if (CanonicalND == ConsumerInstance->TheNamespaceDecl) { // remove the entire Decl if it's in the following form: // * using namespace TheNameSpace; or // * using namespace ::TheNameSpace; NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (!QualifierLoc || ConsumerInstance->isGlobalNamespace(QualifierLoc)) ConsumerInstance->RewriteHelper->removeDecl(D); else ConsumerInstance->removeLastNamespaceFromUsingDecl(D, CanonicalND); } // handle cases like the following: // namespace NS1 { } // namespace NS2 { // namespace NS1 { // void foo() {} // } // namespace NS3 { // using namespace NS1; // void bar() {foo();} // } // } // if we remove NS1, we need to update "using namespace NS1" because "NS1" // conflicts with the global namespace NS1. Note that it could only happen // if NS1 is the first name in a NestedNameSpecifier std::string Name; if (ConsumerInstance->getNewNamedDeclName(CanonicalND, Name)) { ConsumerInstance->replaceFirstNamespaceFromUsingDecl(D, Name); } return true; } bool RemoveNamespaceRewriteVisitor::VisitUsingDecl(UsingDecl *D) { if (ConsumerInstance->isForUsingNamedDecls) return true; if (ConsumerInstance->UselessUsingDecls.count(D)) { ConsumerInstance->RewriteHelper->removeDecl(D); return true; } // check if this UsingDecl refers to the namespaced being removed NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); TransAssert(QualifierLoc && "Bad QualifierLoc!"); NestedNameSpecifierLoc PrefixLoc = QualifierLoc.getPrefix(); const NestedNameSpecifier *NNS = D->getQualifier(); TransAssert(NNS && "Bad NameSpecifier!"); if (ConsumerInstance->isTheNamespaceSpecifier(NNS) && (!PrefixLoc || ConsumerInstance->isGlobalNamespace(PrefixLoc))) { ConsumerInstance->RewriteHelper->removeDecl(D); SkipTraverseNestedNameSpecifier = true; } return true; } bool RemoveNamespaceRewriteVisitor::VisitNamespaceAliasDecl( NamespaceAliasDecl *D) { if (ConsumerInstance->isForUsingNamedDecls) return true; const NamespaceDecl *CanonicalND = D->getNamespace()->getCanonicalDecl(); if (D->getQualifier()) { TraverseNestedNameSpecifierLoc(D->getQualifierLoc()); if (CanonicalND == ConsumerInstance->TheNamespaceDecl) { NestedNameSpecifierLoc QualLoc = D->getQualifierLoc(); SourceLocation QualEndLoc = QualLoc.getEndLoc(); SourceLocation DeclEndLoc = D->getSourceRange().getEnd(); ConsumerInstance->TheRewriter.RemoveText( SourceRange(QualEndLoc, DeclEndLoc)); } } else { if (CanonicalND == ConsumerInstance->TheNamespaceDecl) ConsumerInstance->RewriteHelper->removeDecl(D); } return true; } bool RemoveNamespaceRewriteVisitor::VisitCXXConstructorDecl (CXXConstructorDecl *CtorDecl) { if (ConsumerInstance->isForUsingNamedDecls) return true; const DeclContext *Ctx = CtorDecl->getDeclContext(); const CXXRecordDecl *CXXRD = dyn_cast(Ctx); TransAssert(CXXRD && "Invalid CXXRecordDecl"); std::string Name; if (ConsumerInstance->getNewNamedDeclName(CXXRD, Name)) ConsumerInstance->RewriteHelper->replaceFunctionDeclName(CtorDecl, Name); return true; } // I didn't factor out the common part of this function // into RewriteUtils, because the common part has implicit // dependency on VisitTemplateSpecializationTypeLoc. If in another // transformation we use this utility without implementing // VisitTemplateSpecializationTypeLoc, we will be in trouble. bool RemoveNamespaceRewriteVisitor::VisitCXXDestructorDecl( CXXDestructorDecl *DtorDecl) { if (ConsumerInstance->isForUsingNamedDecls) return true; const DeclContext *Ctx = DtorDecl->getDeclContext(); const CXXRecordDecl *CXXRD = dyn_cast(Ctx); TransAssert(CXXRD && "Invalid CXXRecordDecl"); std::string Name; if (!ConsumerInstance->getNewNamedDeclName(CXXRD, Name)) return true; // Avoid duplicated VisitDtor. // For example, in the code below: // template // class SomeClass { // public: // ~SomeClass() {} // }; // ~SomeClass's TypeLoc is represented as TemplateSpecializationTypeLoc // In this case, ~SomeClass will be renamed from // VisitTemplateSpecializationTypeLoc. DeclarationNameInfo NameInfo = DtorDecl->getNameInfo(); if ( TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) { TypeLoc DtorLoc = TSInfo->getTypeLoc(); if (!DtorLoc.isNull() && (DtorLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)) return true; } ConsumerInstance->RewriteHelper->replaceCXXDestructorDeclName(DtorDecl, Name); return true; } bool RemoveNamespaceRewriteVisitor::VisitCXXMemberCallExpr( CXXMemberCallExpr *CXXCE) { const CXXRecordDecl *CXXRD = CXXCE->getRecordDecl(); // getRecordDEcl could return NULL if getImplicitObjectArgument() // returns NULL if (!CXXRD || ConsumerInstance->isForUsingNamedDecls) return true; std::string Name; // Dtors from UsingNamedDecl can't have conflicts, so it's safe // to get new names from NamedDecl set if (ConsumerInstance->getNewNamedDeclName(CXXRD, Name)) ConsumerInstance->RewriteHelper->replaceCXXDtorCallExpr(CXXCE, Name); return true; } bool RemoveNamespaceRewriteVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { NestedNameSpecifierLoc Loc = DRE->getQualifierLoc(); // traverse NestedNameSpecifier first, because we could probably // ignore rewriting this DeclRefExpr TraverseNestedNameSpecifierLoc(Loc); // Avoid double-visit SkipTraverseNestedNameSpecifier = true; if (SkipRewriteName) { SkipRewriteName = false; return true; } const ValueDecl *OrigDecl = DRE->getDecl(); if (isa(OrigDecl) || isa(OrigDecl) || isa(OrigDecl)) { std::string Name; if (ConsumerInstance->getNewName(OrigDecl, Name)) { ConsumerInstance->TheRewriter.ReplaceText(DRE->getBeginLoc(), OrigDecl->getNameAsString().size(), Name); } } return true; } bool RemoveNamespaceRewriteVisitor::VisitRecordTypeLoc(RecordTypeLoc RTLoc) { const CXXRecordDecl *RD = dyn_cast(RTLoc.getDecl()); if (!RD) return true; std::string Name; if (ConsumerInstance->getNewName(RD, Name)) { ConsumerInstance->RewriteHelper->replaceRecordType(RTLoc, Name); } return true; } bool RemoveNamespaceRewriteVisitor::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TSPLoc) { const Type *Ty = TSPLoc.getTypePtr(); const TemplateSpecializationType *TST = dyn_cast(Ty); TransAssert(TST && "Bad TemplateSpecializationType!"); TemplateName TplName = TST->getTemplateName(); const TemplateDecl *TplD = TplName.getAsTemplateDecl(); TransAssert(TplD && "Invalid TemplateDecl!"); NamedDecl *ND = TplD->getTemplatedDecl(); // in some cases, ND could be NULL, e.g., the // template template parameter code below: // template class BBB> // struct AAA { // template // struct CCC { // static BBB a; // }; // }; // where we don't know BBB if (!ND) return true; const CXXRecordDecl *CXXRD = dyn_cast(ND); if (!CXXRD) return true; std::string Name; if (ConsumerInstance->getNewName(CXXRD, Name)) { SourceLocation LocStart = TSPLoc.getTemplateNameLoc(); ConsumerInstance->TheRewriter.ReplaceText( LocStart, CXXRD->getNameAsString().size(), Name); } return true; } bool RemoveNamespaceRewriteVisitor::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { const Type *Ty = D->getInjectedSpecializationType().getTypePtr(); TransAssert(Ty && "Bad TypePtr!"); const TemplateSpecializationType *TST = dyn_cast(Ty); TransAssert(TST && "Bad TemplateSpecializationType!"); TemplateName TplName = TST->getTemplateName(); const TemplateDecl *TplD = TplName.getAsTemplateDecl(); TransAssert(TplD && "Invalid TemplateDecl!"); NamedDecl *ND = TplD->getTemplatedDecl(); TransAssert(ND && "Invalid NamedDecl!"); const CXXRecordDecl *CXXRD = dyn_cast(ND); TransAssert(CXXRD && "Invalid CXXRecordDecl!"); std::string Name; if (ConsumerInstance->getNewName(CXXRD, Name)) { const TypeSourceInfo *TyInfo = D->getTypeAsWritten(); if (!TyInfo) return true; TypeLoc TyLoc = TyInfo->getTypeLoc(); SourceLocation LocStart = TyLoc.getBeginLoc(); TransAssert(LocStart.isValid() && "Invalid Location!"); ConsumerInstance->TheRewriter.ReplaceText( LocStart, CXXRD->getNameAsString().size(), Name); } return true; } // handle the case where a template specialization type cannot be resolved, e.g. // template struct Base {}; // template struct Derived: public Base { // typename Derived::template Base* p1; // }; bool RemoveNamespaceRewriteVisitor::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc DTSLoc) { const Type *Ty = DTSLoc.getTypePtr(); const DependentTemplateSpecializationType *DTST = dyn_cast(Ty); TransAssert(DTST && "Bad DependentTemplateSpecializationType!"); const IdentifierInfo *IdInfo = DTST->getIdentifier(); std::string IdName = IdInfo->getName().str(); std::string Name; // FIXME: // This isn't quite right, we will generate bad code for some cases, e.g., // namespace NS1 { // template struct Base {}; // template struct Derived: public Base { // typename Derived::template Base* p1; // }; // } // template struct Base {}; // template struct Derived: public Base { // typename Derived::template Base* p1; // }; // For the global Derived template class, we will end up with // typename Derived::template Tran_NS_NS1_Base ..., // which is obviously wrong. // Any way to avoid this bad transformation? if (ConsumerInstance->getNewNameByName(IdName, Name)) { SourceLocation LocStart = DTSLoc.getTemplateNameLoc(); ConsumerInstance->TheRewriter.ReplaceText( LocStart, IdName.size(), Name); } return true; } bool RemoveNamespaceRewriteVisitor::VisitInjectedClassNameTypeLoc( InjectedClassNameTypeLoc TyLoc) { const CXXRecordDecl *CXXRD = TyLoc.getDecl(); TransAssert(CXXRD && "Invalid CXXRecordDecl!"); std::string Name; if (ConsumerInstance->getNewName(CXXRD, Name)) { SourceLocation LocStart = TyLoc.getBeginLoc(); TransAssert(LocStart.isValid() && "Invalid Location!"); ConsumerInstance->TheRewriter.ReplaceText( LocStart, CXXRD->getNameAsString().size(), Name); } return true; } bool RemoveNamespaceRewriteVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TyLoc) { const TypedefNameDecl *D = TyLoc.getTypedefNameDecl(); std::string Name; if (ConsumerInstance->getNewName(D, Name)) { SourceLocation LocStart = TyLoc.getBeginLoc(); ConsumerInstance->TheRewriter.ReplaceText( LocStart, D->getNameAsString().size(), Name); } return true; } bool RemoveNamespaceRewriteVisitor::VisitEnumTypeLoc(EnumTypeLoc TyLoc) { const EnumDecl *D = TyLoc.getDecl(); std::string Name; if (ConsumerInstance->getNewName(D, Name)) { SourceLocation LocStart = TyLoc.getBeginLoc(); ConsumerInstance->TheRewriter.ReplaceText( LocStart, D->getNameAsString().size(), Name); } return true; } // It handles two cases: // * remove the specifier if it refers to TheNamespaceDecl // * replace the specifier with a new name if the corresponding namespace // has a name conflicts, e.g., // namespace NS1 { } // namespace NS2 { // namespace NS1 { // void foo() {} // } // namespace NS3 { // using NS1::foo; // void bar() { foo(); } // } // } // If we remove NS2, then the inner namespace NS1 conflicts with // the global NS1, but "using NS1::foo" refers to the conflicting NS1. bool RemoveNamespaceRewriteVisitor::TraverseNestedNameSpecifierLoc( NestedNameSpecifierLoc QualifierLoc) { SkipRewriteName = false; // Reset the flag if (SkipTraverseNestedNameSpecifier) { SkipTraverseNestedNameSpecifier = false; return true; } if (!QualifierLoc || QualifierLoc.getBeginLoc().isInvalid()) return true; SmallVector QualifierLocs; for (; QualifierLoc; QualifierLoc = QualifierLoc.getPrefix()) QualifierLocs.push_back(QualifierLoc); while (!QualifierLocs.empty()) { NestedNameSpecifierLoc Loc = QualifierLocs.pop_back_val(); NestedNameSpecifier *NNS = Loc.getNestedNameSpecifier(); NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); const NamespaceDecl *ND = NULL; switch (Kind) { case NestedNameSpecifier::Namespace: { ND = NNS->getAsNamespace()->getCanonicalDecl(); break; } case NestedNameSpecifier::NamespaceAlias: { const NamespaceAliasDecl *NAD = NNS->getAsNamespaceAlias(); if (!NAD->getQualifier()) ND = NAD->getNamespace()->getCanonicalDecl(); break; } case NestedNameSpecifier::TypeSpec: // Fall-through case NestedNameSpecifier::TypeSpecWithTemplate: TraverseTypeLoc(Loc.getTypeLoc()); break; default: break; } if (!ND) continue; if (ND == ConsumerInstance->TheNamespaceDecl) { ConsumerInstance->RewriteHelper->removeSpecifier(Loc); continue; } std::string SpecifierName; if (Loc.getBeginLoc().isInvalid()) continue; ConsumerInstance->RewriteHelper->getSpecifierAsString(Loc, SpecifierName); std::string NDName = ND->getNameAsString(); std::string Name = ""; ConsumerInstance->getNewName(ND, Name); // Skip it if this specifier is the same as ND's name. // Note that the above case could only happen for UsingNamedDecls if (ConsumerInstance->isForUsingNamedDecls && (SpecifierName == NDName)) { // It could happen for example: // namespace NS1 { } // namespace NS2 { // using namespace NS1; // void bar() { NS1::foo(); } // } // If we remove NS2, then the guard below avoids renaming // NS1::foo to NS1::foo::foo. if (Name.empty()) { SkipRewriteName = true; return true; } // another case to handle: // namespace NS1 { // namespace NS2 { // void foo() {} // } // } // namespace NS3 { // using namespace NS1; // void bar() { NS2::foo(); } // } // If we remove NS3, we do need to rename NS2::foo as NS1::NS2::foo if (!ConsumerInstance->isSuffix(Name, SpecifierName)) { SkipRewriteName = true; return true; } } if (!Name.empty()) { ConsumerInstance->RewriteHelper->replaceSpecifier(Loc, Name); SkipRewriteName = true; return true; } } return true; } void RemoveNamespace::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveNamespaceASTVisitor(this); RewriteVisitor = new RemoveNamespaceRewriteVisitor(this); } bool RemoveNamespace::HandleTopLevelDecl(DeclGroupRef D) { // Nothing to do return true; } void RemoveNamespace::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt()) { ValidInstanceNum = 0; } else { // Invoke CollectionVisitor here because we need full DeclContext // to resolve name conflicts. Full ASTs has been built at this point. CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); TransAssert(TheNamespaceDecl && "NULL TheNamespaceDecl!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); // First rename UsingNamedDecls, i.e., conflicting names // from other namespaces. // FIXME: isForUsingNamedDecls flag is quite ugly, // need a way to remove it isForUsingNamedDecls = true; RewriteVisitor->TraverseDecl(TheNamespaceDecl); isForUsingNamedDecls = false; rewriteNamedDecls(); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveNamespace::rewriteNamedDecls(void) { for (NamedDeclToNameMap::const_iterator I = NamedDeclToNewName.begin(), E = NamedDeclToNewName.end(); I != E; ++I) { const NamedDecl *D = (*I).first; std::string Name = (*I).second; Decl::Kind K = D->getKind(); switch (K) { case Decl::Function: case Decl::CXXMethod: { // Check replaceFunctionDecl in RewriteUtils.cpp for the reason that // we need a special case for FunctionDecl const FunctionDecl *FD = dyn_cast(D); RewriteHelper->replaceFunctionDeclName(FD, Name); break; } case Decl::ClassTemplateSpecialization: { // Skip this case, which will be handled by // VisitTemplateSpecializationTypeLoc break; } default: RewriteHelper->replaceNamedDeclName(D, Name); } } } bool RemoveNamespace::isValidNamedDeclKind(const NamedDecl *ND) { return (isa(ND) || isa(ND) || isa(ND) || isa(ND) || isa(ND)); } bool RemoveNamespace::hasNameConflict(const NamedDecl *ND, const DeclContext *ParentCtx) { // we cannot lookup names from LinkageSpecDecl, e.g., // extern "C++" { ... } if (dyn_cast(ParentCtx)) return false; DeclarationName Name = ND->getDeclName(); DeclContext::lookup_result Result = ParentCtx->lookup(Name); return !Result.empty(); } // We always prepend the Prefix string to EnumConstantDecl if ParentCtx // is NULL void RemoveNamespace::handleOneEnumDecl(const EnumDecl *ED, const std::string &Prefix, NamedDeclToNameMap &NameMap, const DeclContext *ParentCtx) { for (EnumDecl::enumerator_iterator I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) { EnumConstantDecl *ECD = (*I); if (!ParentCtx || hasNameConflict(ECD, ParentCtx)) { const IdentifierInfo *IdInfo = ECD->getIdentifier(); std::string NewName = Prefix; NewName += IdInfo->getName(); NameMap[ECD] = NewName; } } } // A using declaration in the removed namespace could cause // name conflict, e.g., // namespace NS1 { // void foo(void) {} // } // namespace NS2 { // using NS1::foo; // void bar() { ... foo(); ... } // } // void foo() {...} // void func() {... foo(); ...} // if we remove NS2, then foo() in func() will become ambiguous. // In this case, we need to replace the first invocation of foo() // with NS1::foo() void RemoveNamespace::handleOneUsingShadowDecl(const UsingShadowDecl *UD, const DeclContext *ParentCtx) { const NamedDecl *ND = UD->getTargetDecl(); if (!hasNameConflict(ND, ParentCtx)) return; std::string NewName; const UsingDecl *D = UD->getUsingDecl(); NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); NestedNameSpecifier *NNS = QualifierLoc.getNestedNameSpecifier(); // QualifierLoc could be ::foo, whose PrefixLoc is invalid, e.g., // void foo(); // namespace NS2 { // using ::foo; // void bar () { foo(); } // } if (NNS->getKind() != NestedNameSpecifier::Global) { // NestedNameSpecifierLoc PrefixLoc = QualifierLoc.getPrefix(); RewriteHelper->getQualifierAsString(QualifierLoc, NewName); } if ( const TemplateDecl *TD = dyn_cast(ND) ) { ND = TD->getTemplatedDecl(); } // NewName += "::"; const FunctionDecl *FD = dyn_cast(ND); if (FD && FD->isOverloadedOperator()) { const char *Op = clang::getOperatorSpelling(FD->getOverloadedOperator()); std::string OpStr(Op); NewName += ("operator::" + OpStr); } else { const IdentifierInfo *IdInfo = ND->getIdentifier(); TransAssert(IdInfo && "Invalid IdentifierInfo!"); NewName += IdInfo->getName(); } UsingNamedDeclToNewName[ND] = NewName; // the tied UsingDecl becomes useless, and hence it's removable UselessUsingDecls.insert(D); } // For the similar reason as dealing with using declarations, // we need to resolve the possible name conflicts introduced by // using directives void RemoveNamespace::handleOneUsingDirectiveDecl(const UsingDirectiveDecl *UD, const DeclContext *ParentCtx) { const NamespaceDecl *ND = UD->getNominatedNamespace(); // It could happen, for example: // namespace NS { // namespace { // int x; // } // } // where the inner anonymous namespace will have an implicit using directive // declaration if (ND->isAnonymousNamespace()) return; std::string NamespaceName = ND->getNameAsString(); for (DeclContext::decl_iterator I = ND->decls_begin(), E = ND->decls_end(); I != E; ++I) { const NamedDecl *NamedD = dyn_cast(*I); if (!NamedD) continue; if (!isValidNamedDeclKind(NamedD)) continue; std::string NewName = ""; if ( NestedNameSpecifierLoc QualifierLoc = UD->getQualifierLoc() ) { RewriteHelper->getQualifierAsString(QualifierLoc, NewName); } NewName += NamespaceName; NewName += "::"; if ( const TemplateDecl *TD = dyn_cast(NamedD) ) { NamedD = TD->getTemplatedDecl(); } else if (const EnumDecl *ED = dyn_cast(NamedD)) { handleOneEnumDecl(ED, NewName, UsingNamedDeclToNewName, NULL); } const FunctionDecl *FD = dyn_cast(NamedD); if (FD && FD->isOverloadedOperator()) { const char *Op = clang::getOperatorSpelling(FD->getOverloadedOperator()); std::string OpStr(Op); NewName += ("operator::" + OpStr); } else { const IdentifierInfo *IdInfo = NamedD->getIdentifier(); if (!IdInfo) continue; NewName += IdInfo->getName(); } UsingNamedDeclToNewName[NamedD] = NewName; } // We always remove this using directive, and in ThenNamespaceDecl // append the corresponding namespace specifier to all names from the // used namespace. The reason is that the conlicted name in the outter // namespace could appear after TheNamespaceDecl, e.g., // namespace NS1 { // void foo() {} // void fiz() {} // } // namespace NS2 { // using namespace NS1; // int bar() { foo(); } // } // void fiz() {} // void f() { fiz(); } // If we keep "using namespace NS1" after removing NS2, then we will // end up with an ambiguous name fiz // Consequently, we will add a few unecessary namespace qualifiers to // those without conflicting names. It's a trade-off. UselessUsingDirectiveDecls.insert(UD); } void RemoveNamespace::handleOneNamedDecl(const NamedDecl *ND, const DeclContext *ParentCtx, const std::string &NamespaceName) { Decl::Kind K = ND->getKind(); switch (K) { case Decl::UsingShadow: { const UsingShadowDecl *D = dyn_cast(ND); handleOneUsingShadowDecl(D, ParentCtx); return; } case Decl::UsingDirective: { const UsingDirectiveDecl *D = dyn_cast(ND); handleOneUsingDirectiveDecl(D, ParentCtx); return; } default: if (!isValidNamedDeclKind(ND)) return; if (!hasNameConflict(ND, ParentCtx)) return; std::string NewName = NamePrefix + NamespaceName; const IdentifierInfo *IdInfo = ND->getIdentifier(); NewName += "_"; if ( const TemplateDecl *TD = dyn_cast(ND) ) { ND = TD->getTemplatedDecl(); } else if (const EnumDecl *ED = dyn_cast(ND)) { handleOneEnumDecl(ED, NewName, NamedDeclToNewName, ParentCtx); } // This is bad. Any better solution? Maybe we need to change // the overloaded operator to a regular function? if (const FunctionDecl *FD = dyn_cast(ND)) { if (FD->isOverloadedOperator()) return; } TransAssert(IdInfo && "Invalid IdentifierInfo!"); NewName += IdInfo->getName(); NamedDeclToNewName[ND] = NewName; } } void RemoveNamespace::addNamedDeclsFromNamespace(const NamespaceDecl *ND) { // We don't care about name-lookup for friend's functions, so just // retrive ParentContext rather than LookupParent const DeclContext *ParentCtx = ND->getParent(); std::string NamespaceName; if (ND->isAnonymousNamespace()) { std::stringstream TmpSS; TmpSS << AnonNamePrefix << AnonNamespaceCounter; NamespaceName = TmpSS.str(); AnonNamespaceCounter++; } else { NamespaceName = ND->getNameAsString(); } for (DeclContext::decl_iterator I = ND->decls_begin(), E = ND->decls_end(); I != E; ++I) { if ( const NamedDecl *D = dyn_cast(*I) ) handleOneNamedDecl(D, ParentCtx, NamespaceName); } } bool RemoveNamespace::handleOneNamespaceDecl(NamespaceDecl *ND) { if (isInIncludedFile(ND)) return true; NamespaceDecl *CanonicalND = ND->getCanonicalDecl(); if (VisitedND.count(CanonicalND)) { if (TheNamespaceDecl == CanonicalND) { addNamedDeclsFromNamespace(ND); } return true; } VisitedND.insert(CanonicalND); ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheNamespaceDecl = CanonicalND; addNamedDeclsFromNamespace(ND); } return true; } void RemoveNamespace::removeNamespace(const NamespaceDecl *ND) { // Remove the right brace first SourceLocation RBLoc = ND->getRBraceLoc(); if (RBLoc.isValid()) { if (RBLoc.isMacroID()) { TheRewriter.RemoveText(SrcManager->getExpansionRange(RBLoc).getAsRange()); } else { TheRewriter.RemoveText(RBLoc, 1); } } // Then remove name and the left brace SourceLocation StartLoc = ND->getBeginLoc(); TransAssert(StartLoc.isValid() && "Invalid Namespace LocStart!"); StartLoc = SrcManager->getFileLoc(StartLoc); SourceLocation EndLoc; if (ND->decls_empty()) { EndLoc = RBLoc; } else { DeclContext::decl_iterator I = ND->decls_begin(); EndLoc = SrcManager->getFileLoc(dyn_cast(*I)->getBeginLoc()); } if (StartLoc != EndLoc) { EndLoc = EndLoc.getLocWithOffset(-1); SourceRange NewRange(StartLoc, EndLoc); int RangeSize = TheRewriter.getRangeSize(NewRange); TransAssert((RangeSize != -1) && "Bad Namespace Range!"); const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::string NDStr(StartBuf, RangeSize); size_t Pos = NDStr.find('{'); if (Pos != std::string::npos) EndLoc = StartLoc.getLocWithOffset(Pos); } TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); } bool RemoveNamespace::getNewNameFromNameMap(const NamedDecl *ND, std::string &Name, const NamedDeclToNameMap &NameMap) { NamedDeclToNameMap::const_iterator Pos = NameMap.find(ND); if (Pos == NameMap.end()) return false; Name = (*Pos).second; return true; } bool RemoveNamespace::getNewNameByNameFromNameMap(const std::string &Name, std::string &NewName, const NamedDeclToNameMap &NameMap) { for (NamedDeclToNameMap::const_iterator I = NameMap.begin(), E = NameMap.end(); I != E; ++I) { const NamedDecl *D = (*I).first; const CXXRecordDecl *CXXRD = dyn_cast(D); if (!CXXRD) continue; if (Name == CXXRD->getNameAsString()) { NewName = (*I).second; return true; } } return false; } bool RemoveNamespace::getNewNamedDeclName(const NamedDecl *ND, std::string &Name) { return getNewNameFromNameMap(ND, Name, NamedDeclToNewName); } bool RemoveNamespace::getNewUsingNamedDeclName(const NamedDecl *ND, std::string &Name) { return getNewNameFromNameMap(ND, Name, UsingNamedDeclToNewName); } bool RemoveNamespace::getNewName(const NamedDecl *ND, std::string &Name) { if (isForUsingNamedDecls) return getNewUsingNamedDeclName(ND, Name); else return getNewNamedDeclName(ND, Name); } bool RemoveNamespace::getNewNameByName(const std::string &Name, std::string &NewName) { if (isForUsingNamedDecls) return getNewNameByNameFromNameMap(Name, NewName, UsingNamedDeclToNewName); else return getNewNameByNameFromNameMap(Name, NewName, NamedDeclToNewName); } bool RemoveNamespace::isGlobalNamespace(NestedNameSpecifierLoc Loc) { NestedNameSpecifier *NNS = Loc.getNestedNameSpecifier(); return (NNS->getKind() == NestedNameSpecifier::Global); } bool RemoveNamespace::isTheNamespaceSpecifier(const NestedNameSpecifier *NNS) { NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); switch (Kind) { case NestedNameSpecifier::Namespace: { const NamespaceDecl *CanonicalND = NNS->getAsNamespace()->getCanonicalDecl(); return (CanonicalND == TheNamespaceDecl); } case NestedNameSpecifier::NamespaceAlias: { const NamespaceAliasDecl *NAD = NNS->getAsNamespaceAlias(); // we remove the namealias only when it doesn't have nestedspecifier if (NAD->getQualifier()) return false; const NamespaceDecl *CanonicalND = NAD->getNamespace()->getCanonicalDecl(); return (CanonicalND == TheNamespaceDecl); } default: return false; } TransAssert(0 && "Unreachable code!"); return false; } bool RemoveNamespace::isSuffix(std::string &Name, std::string &SpecifierName) { size_t NameLen = Name.length(); std::string Suffix = "::" + SpecifierName; size_t SuffixLen = Suffix.length(); if (NameLen <= SuffixLen) return false; return !Suffix.compare(0, SuffixLen, Name, NameLen - SuffixLen, SuffixLen); } void RemoveNamespace::replaceFirstNamespaceFromUsingDecl( const UsingDirectiveDecl *D, const std::string &Name) { const NamespaceDecl *ND = D->getNominatedNamespace(); SourceLocation IdLocStart = D->getIdentLocation(); TheRewriter.ReplaceText(IdLocStart, ND->getNameAsString().length(), Name); } void RemoveNamespace::removeLastNamespaceFromUsingDecl( const UsingDirectiveDecl *D, const NamespaceDecl *ND) { SourceLocation IdLocStart = D->getIdentLocation(); SourceRange DeclSourceRange = D->getSourceRange(); SourceLocation DeclLocStart = DeclSourceRange.getBegin(); const char *IdStartBuf = SrcManager->getCharacterData(IdLocStart); const char *DeclStartBuf = SrcManager->getCharacterData(DeclLocStart); unsigned Count = 0; int Offset = 0; while (IdStartBuf != DeclStartBuf) { if (*IdStartBuf != ':') { IdStartBuf--; Offset--; continue; } Count++; if (Count == 2) { break; } Offset--; IdStartBuf--; } TransAssert((Count == 2) && "Bad NestedNamespaceSpecifier!"); TransAssert((Offset < 0) && "Bad Offset Value!"); IdLocStart = IdLocStart.getLocWithOffset(Offset); TheRewriter.RemoveText(IdLocStart, ND->getNameAsString().length() - Offset); } RemoveNamespace::~RemoveNamespace(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/RemoveNamespace.h000066400000000000000000000126561402162750500203210ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_NAMESPACE_H #define REMOVE_NAMESPACE_H #include #include "Transformation.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/DenseMap.h" #include "clang/AST/NestedNameSpecifier.h" namespace clang { class DeclGroupRef; class ASTContext; class NamespaceDecl; class NamedDecl; class DeclContext; class UsingDirectiveDecl; class UsingShadowDecl; class UsingDecl; class EnumDecl; } class RemoveNamespaceASTVisitor; class RemoveNamespaceRewriteVisitor; class RemoveNamespace : public Transformation { friend class RemoveNamespaceASTVisitor; friend class RemoveNamespaceRewriteVisitor; public: RemoveNamespace(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheNamespaceDecl(NULL), NamePrefix("Trans_NS_"), AnonNamePrefix("Trans_Anon_NS"), AnonNamespaceCounter(0), isForUsingNamedDecls(false) { } ~RemoveNamespace(void); private: typedef llvm::SmallPtrSet NamespaceDeclSet; typedef llvm::SmallPtrSet UsingDeclSet; typedef llvm::SmallPtrSet UsingDirectiveDeclSet; typedef llvm::DenseMap NamedDeclToNameMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addNamedDeclsFromNamespace(const clang::NamespaceDecl *ND); bool handleOneNamespaceDecl(clang::NamespaceDecl *ND); void removeNamespace(const clang::NamespaceDecl *ND); void removeUsingOrUsingDirectiveDecl(const clang::Decl *D); void handleOneNamedDecl(const clang::NamedDecl *ND, const clang::DeclContext *ParentCtx, const std::string &NamespaceName); bool hasNameConflict(const clang::NamedDecl *ND, const clang::DeclContext *ParentCtx); bool isValidNamedDeclKind(const clang::NamedDecl *ND); void handleOneEnumDecl(const clang::EnumDecl *ED, const std::string &Prefix, NamedDeclToNameMap &NameMap, const clang::DeclContext *ParentCtx); void handleOneUsingShadowDecl(const clang::UsingShadowDecl *UD, const clang::DeclContext *ParentCtx); void handleOneUsingDirectiveDecl(const clang::UsingDirectiveDecl *UD, const clang::DeclContext *ParentCtx); void rewriteNamedDecls(void); bool getNewNameFromNameMap(const clang::NamedDecl *ND, std::string &Name, const NamedDeclToNameMap &NameMap); bool getNewNameByNameFromNameMap(const std::string &Name, std::string &NewName, const NamedDeclToNameMap &NameMap); bool getNewNamedDeclName(const clang::NamedDecl *ND, std::string &Name); bool getNewUsingNamedDeclName(const clang::NamedDecl *ND, std::string &Name); bool getNewName(const clang::NamedDecl *ND, std::string &Name); bool getNewNameByName(const std::string &Name, std::string &NewName); bool isGlobalNamespace(clang::NestedNameSpecifierLoc Loc); bool isTheNamespaceSpecifier(const clang::NestedNameSpecifier *NNS); void removeLastNamespaceFromUsingDecl(const clang::UsingDirectiveDecl *D, const clang::NamespaceDecl *ND); void replaceFirstNamespaceFromUsingDecl(const clang::UsingDirectiveDecl *D, const std::string &Name); bool isSuffix(std::string &Name, std::string &SpecifierName); NamespaceDeclSet VisitedND; UsingDeclSet UselessUsingDecls; UsingDirectiveDeclSet UselessUsingDirectiveDecls; // a mapping from NamedDecls in TheNamespaceDecl used in TheNamespaceDecl // to their new names after TheNamespaceDecl is removed. This map only // stores those NamedDecls which need to be renamed. NamedDeclToNameMap NamedDeclToNewName; // a mapping from NamedDecl in other namespaces used in TheNamespaceDecl // to their new names after TheNamespaceDecl is removed. NamedDeclToNameMap UsingNamedDeclToNewName; RemoveNamespaceASTVisitor *CollectionVisitor; RemoveNamespaceRewriteVisitor *RewriteVisitor; clang::NamespaceDecl *TheNamespaceDecl; const std::string NamePrefix; // Prefix for anonymous namespaces const std::string AnonNamePrefix; unsigned AnonNamespaceCounter; // a flag to indicate if we are working on renaming UsingNamedDecl // The purpose of this flag is to avoid double visit. // The RemoveNamespaceRewriteVisitor are used twice: // * one for TheNamespaceDecl. In this case, we only rename UsingNamedDecls // without doing any other work // * another is for NamedDecls belonging to TheNamespaceDecl bool isForUsingNamedDecls; // Unimplemented RemoveNamespace(void); RemoveNamespace(const RemoveNamespace &); void operator=(const RemoveNamespace &); }; #endif cvise-2.3.0/clang_delta/RemoveNestedFunction.cpp000066400000000000000000000375531402162750500217130ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveNestedFunction.h" #include #include "llvm/ADT/SmallVector.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonStatementVisitor.h" using namespace clang; static const char *DescriptionMsg = "Remove a nested function invocation from its enclosing \ expression. The transformation will create a temporary \ variable with the correct type, assgin the return value \ of the selected nested function to the created variable, \ and replace the function invocation with this temporary \ variable. (Note that this transformation is unsound because \ it changes the semantics of loop executions in some cases. \n"; static RegisterTransformation Trans("remove-nested-function", DescriptionMsg); class RNFCollectionVisitor : public RecursiveASTVisitor { public: explicit RNFCollectionVisitor(RemoveNestedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: RemoveNestedFunction *ConsumerInstance; }; class RNFStatementVisitor : public CommonStatementVisitor { public: explicit RNFStatementVisitor(RemoveNestedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitCallExpr(CallExpr *CallE); bool VisitStmtExpr(StmtExpr *SE); private: RemoveNestedFunction *ConsumerInstance; }; bool RNFCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || !FD->isThisDeclarationADefinition()) return true; ConsumerInstance->StmtVisitor->setCurrentFunctionDecl(FD); ConsumerInstance->StmtVisitor->TraverseDecl(FD); ConsumerInstance->StmtVisitor->setCurrentFunctionDecl(NULL); return true; } bool RNFStatementVisitor::VisitStmtExpr(StmtExpr *SE) { CompoundStmt *CS = SE->getSubStmt(); if (ConsumerInstance->CallExprQueue.empty()) { TraverseStmt(CS); return false; } CallExpr *CallE = ConsumerInstance->CallExprQueue.back(); CurrentStmt = CallE; for (clang::CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); I != E; ++I) { TraverseStmt(*I); } return false; } bool RNFStatementVisitor::VisitCallExpr(CallExpr *CallE) { if (const CXXOperatorCallExpr *OpE = dyn_cast(CallE)) { if (ConsumerInstance->isInvalidOperator(OpE)) return true; } if (CurrentStmt && (std::find(ConsumerInstance->ValidCallExprs.begin(), ConsumerInstance->ValidCallExprs.end(), CallE) == ConsumerInstance->ValidCallExprs.end()) && !ConsumerInstance->CallExprQueue.empty()) { ConsumerInstance->ValidInstanceNum++; ConsumerInstance->ValidCallExprs.push_back(CallE); if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheFuncDecl = CurrentFuncDecl; ConsumerInstance->TheStmt = CurrentStmt; ConsumerInstance->TheCallExpr = CallE; ConsumerInstance->NeedParen = NeedParen; } } ConsumerInstance->CallExprQueue.push_back(CallE); for (CallExpr::arg_iterator I = CallE->arg_begin(), E = CallE->arg_end(); I != E; ++I) { Expr *Exp = *I; TraverseStmt(Exp); } ConsumerInstance->CallExprQueue.pop_back(); return true; } void RemoveNestedFunction::Initialize(ASTContext &context) { Transformation::Initialize(context); NestedInvocationVisitor = new RNFCollectionVisitor(this); StmtVisitor = new RNFStatementVisitor(this); NameQueryWrap = new TransNameQueryWrap(RewriteHelper->getTmpVarNamePrefix()); } bool RemoveNestedFunction::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { NestedInvocationVisitor->TraverseDecl(*I); } return true; } void RemoveNestedFunction::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransAssert(TheStmt && "NULL TheStmt!"); TransAssert(TheCallExpr && "NULL TheCallExpr"); NameQueryWrap->TraverseDecl(Ctx.getTranslationUnitDecl()); addNewTmpVariable(Ctx); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveNestedFunction::getVarStrForTemplateSpecialization( std::string &VarStr, const TemplateSpecializationType *TST) { unsigned NumArgs = TST->getNumArgs(); if (NumArgs == 0) { return; } std::string ArgStr; llvm::raw_string_ostream Stream(ArgStr); TST->getArg(0).print(Context->getPrintingPolicy(), Stream); for (unsigned I = 1; I < NumArgs; ++I) { const TemplateArgument &Arg = TST->getArg(I); Stream << ", "; Arg.print(Context->getPrintingPolicy(), Stream); } size_t BeginPos = VarStr.find_first_of('<'); size_t EndPos = VarStr.find_last_of('>'); TransAssert((BeginPos != std::string::npos) && "Cannot find < !"); TransAssert((EndPos != std::string::npos) && "Cannot find > !"); TransAssert((EndPos > BeginPos) && "Invalid <> pair!"); VarStr.replace(BeginPos + 1, (EndPos - BeginPos - 1), Stream.str()); } void RemoveNestedFunction::getNewTmpVariable(const QualType &QT, std::string &VarStr) { QT.getAsStringInternal(VarStr, Context->getPrintingPolicy()); } void RemoveNestedFunction::getNewIntTmpVariable(std::string &VarStr) { VarStr = "int " + VarStr; } void RemoveNestedFunction::getNewAutoTmpVariable(std::string &VarStr) { VarStr = "auto " + VarStr; } void RemoveNestedFunction::addNewTmpVariable(ASTContext &ASTCtx) { std::string VarStr; getNewTmpVariableStr(ASTCtx, VarStr); if (TransformationManager::isCXXLangOpt()) { // TheStmt and TheCallExpr may share the same start location, e.g.. // TheCallExpr is a CXXOperatorCallExpr. In this case, we just replace // TheCallExpr with tmp variable's definition and the tmp variable. // Otherwise, we would end up with assertion failure, because we // modify the same location twice (through addnewAssignStmtBefore // and replaceExpr. if (TheStmt->getBeginLoc() == TheCallExpr->getBeginLoc()) { std::string ExprStr; RewriteHelper->getExprString(TheCallExpr, ExprStr); VarStr += " = " + ExprStr + ";\n" + TmpVarName; RewriteHelper->replaceExpr(TheCallExpr, VarStr); return; } RewriteHelper->addNewAssignStmtBefore(TheStmt, VarStr, TheCallExpr, NeedParen); } else { RewriteHelper->addLocalVarToFunc(VarStr + ";", TheFuncDecl); RewriteHelper->addNewAssignStmtBefore(TheStmt, getTmpVarName(), TheCallExpr, NeedParen); } RewriteHelper->replaceExpr(TheCallExpr, TmpVarName); } void RemoveNestedFunction::getNewTmpVariableStr(ASTContext &ASTCtx, std::string &VarStr) { std::stringstream SS; unsigned int NamePostfix = NameQueryWrap->getMaxNamePostfix(); SS << RewriteHelper->getTmpVarNamePrefix() << (NamePostfix + 1); VarStr = SS.str(); setTmpVarName(VarStr); QualType QT; const Expr *E = TheCallExpr->getCallee(); if (const UnresolvedLookupExpr *UE = dyn_cast(E)) { // clang doesn't always resolve CallExpr's callee. For example: // template int foo1(int p) {return p;} // template int foo2(int p) {return p;} // template // void bar(void) { foo1(foo2(1)); } // foo2(1) has BuiltinType and hence // TheCallExpr->getCallReturnType() will segfault. // In this case, we have to lookup a corresponding function decl DeclarationName DName = UE->getName(); TransAssert(((DName.getNameKind() == DeclarationName::Identifier) || (DName.getNameKind() == DeclarationName::CXXOperatorName)) && "Not an indentifier!"); const FunctionDecl *FD = NULL; if (const NestedNameSpecifier *NNS = UE->getQualifier()) { if (const DeclContext *Ctx = getDeclContextFromSpecifier(NNS)) { DeclContextSet VisitedCtxs; FD = lookupFunctionDecl(DName, Ctx, VisitedCtxs); } } if (!FD) { DeclContextSet VisitedCtxs; FD = lookupFunctionDecl(DName, TheFuncDecl->getLookupParent(), VisitedCtxs); } // give up and generate a tmp var of int type, e.g.: // template struct S { // T x; // template void foo(A &a0) { x(y(a0)); } // }; if (!FD) return getNewIntTmpVariable(VarStr); QT = FD->getReturnType(); //FIXME: This is actually not quite correct, we should get the instantiated // type here. return getNewTmpVariable(QT, VarStr); } if (const UnresolvedMemberExpr *UM = dyn_cast(E)) { DeclarationName DName = UM->getMemberName(); const CXXRecordDecl *CXXRD = UM->getNamingClass(); DeclContextSet VisitedCtxs; const FunctionDecl *FD = lookupFunctionDecl(DName, CXXRD, VisitedCtxs); // FIXME: try to resolve FD here if (FD) QT = FD->getReturnType(); return getNewTmpVariable(QT, VarStr); } if (const CXXTemporaryObjectExpr *CXXTE = dyn_cast(E)) { const CXXConstructorDecl *CXXCtor = CXXTE->getConstructor(); QT = CXXCtor->getThisType(); return getNewTmpVariable(QT, VarStr); } if (const CXXTemporaryObjectExpr *CXXTE = dyn_cast(E)) { const CXXConstructorDecl *CXXCtor = CXXTE->getConstructor(); QT = CXXCtor->getThisType(); return getNewTmpVariable(QT, VarStr); } if (const CXXDependentScopeMemberExpr *ME = dyn_cast(E)) { if (ME->isImplicitAccess()) return; DeclarationName DName = ME->getMember(); TransAssert((DName.getNameKind() == DeclarationName::Identifier) && "Not an indentifier!"); const Expr *E = ME->getBase(); TransAssert(E && "NULL Base Expr!"); const Expr *BaseE = E->IgnoreParens(); // handle cases where base expr or member name is dependent, e.g., // template // class S { // int f1(int p1) { return p1; }; // int f2(int p2) { return p2; }; // void f3(void); // }; // template // void S::f3(void) // { // f1(this->f2(1)); // } // where this->f2(1) is a CXXDependentScopeMemberExpr if (dyn_cast(BaseE)) { const DeclContext *Ctx = TheFuncDecl->getLookupParent(); TransAssert(Ctx && "Bad DeclContext!"); DeclContextSet VisitedCtxs; const FunctionDecl *FD = lookupFunctionDecl(DName, Ctx, VisitedCtxs); TransAssert(FD && "Cannot resolve DName!"); QT = FD->getReturnType(); return getNewTmpVariable(QT, VarStr); } // handle other cases where lookupDeclContext is different from // the current CXXRecord, e.g., const Type *Ty = ME->getBaseType().getTypePtr(); if (const DeclContext *Ctx = getBaseDeclFromType(Ty)) { DeclContextSet VisitedCtxs; const FunctionDecl *FD = lookupFunctionDecl(DName, Ctx, VisitedCtxs); if (!FD) { return getNewTmpVariable(QT, VarStr); } QT = FD->getReturnType(); const Type *RVTy = QT.getTypePtr(); if (RVTy->getAs()) { // handle cases like: // template struct D { // D f(); // }; // template void foo(D); // template void bar () { // D G; // foo(G.f()); // } // in this case, seems it's hard to retrieve the instantiated type // of f's return type, because `D G' is dependent. I tried // findSpecialization from ClassTemplateDecl, but it didn't work. // So use a really ugly way, i.e., manipulating strings... const TemplateSpecializationType *TST = Ty->getAs(); TransAssert(TST && "Invalid TemplateSpecialization Type!"); QT.getAsStringInternal(VarStr, Context->getPrintingPolicy()); return getVarStrForTemplateSpecialization(VarStr, TST); } else { // other cases: // template struct D { // int f(); // }; // void foo(int); // template void bar () { // D G; // foo(G.f()); // } return getNewTmpVariable(QT, VarStr); } } else { // template struct D { // D f(); // D operator[] (int); // }; // template void foo(D); // template void bar () { // D G; // foo(G[0].f()); // } // In this case, G[0] is of BuiltinType. // But why does clang represent a dependent type as BuiltinType here? TransAssert((Ty->getAs() || Ty->getAs() || Ty->getAs() || Ty->getAs()) && "Uncaught Type"); // FIXME: This is incorrect! // a couple of questions // - how can we find a correct DeclContext where we could lookup f? // - can we obtain the dependent template argument from BuiltinType? // Probably we cannot do these? Comments from lib/AST/ASTContext.cpp: // // Placeholder type for type-dependent expressions whose type is // completely unknown. No code should ever check a type against // DependentTy and users should never see it; however, it is here to // help diagnose failures to properly check for type-dependent // expressions. return getNewIntTmpVariable(VarStr); } } // We can't resolve dependent scoped DeclRefExpr, and just make it // type of int. if (dyn_cast(E)) { return getNewAutoTmpVariable(VarStr); } const Type *CalleeType = E->getType().getTypePtr(); // template struct S { // T1 x; T2 y; // template void foo(A &a0) { x(y(a0)); } // }; if (const TemplateTypeParmType *PT = dyn_cast(CalleeType)) { const TemplateTypeParmDecl *PD = PT->getDecl(); std::string DStr = PD->getNameAsString(); VarStr = DStr + " " + VarStr; return; } if (dyn_cast(CalleeType)) { VarStr = "auto " + VarStr; return; } QT = TheCallExpr->getCallReturnType(ASTCtx); getNewTmpVariable( QT.getTypePtr()->getUnqualifiedDesugaredType()->getCanonicalTypeInternal(), VarStr); } bool RemoveNestedFunction::isInvalidOperator(const CXXOperatorCallExpr *OpE) { OverloadedOperatorKind K = OpE->getOperator(); // ISSUE: overloaded Equal-family operators cause bad recursion, // omit it for now. switch (K) { case OO_Equal: case OO_EqualEqual: case OO_PlusEqual: case OO_MinusEqual: case OO_StarEqual: case OO_SlashEqual: case OO_PercentEqual: case OO_CaretEqual: case OO_AmpEqual: case OO_PipeEqual: case OO_LessLessEqual: case OO_GreaterGreaterEqual: case OO_ExclaimEqual: case OO_LessEqual: case OO_LessLess: case OO_GreaterEqual: // Fall-through return true; default: return false; } } RemoveNestedFunction::~RemoveNestedFunction(void) { delete NestedInvocationVisitor; delete StmtVisitor; delete NameQueryWrap; } cvise-2.3.0/clang_delta/RemoveNestedFunction.h000066400000000000000000000051701402162750500213460ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2014, 2016, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_NESTED_FUNCTION_H #define REMOVE_NESTED_FUNCTION_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class Stmt; class CallExpr; class DeclarationName; class DeclContext; class NestedNameSpecifier; class CXXOperatorCallExpr; class QualType; } class RNFCollectionVisitor; class RNFStatementVisitor; class RemoveNestedFunction : public Transformation { friend class RNFCollectionVisitor; friend class RNFStatementVisitor; public: RemoveNestedFunction(const char *TransName, const char *Desc) : Transformation(TransName, Desc), NestedInvocationVisitor(NULL), StmtVisitor(NULL), NameQueryWrap(NULL), TheFuncDecl(NULL), TheStmt(NULL), TheCallExpr(NULL), TmpVarName(""), NeedParen(false) { } ~RemoveNestedFunction(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void getNewTmpVariableStr(clang::ASTContext &ASTCtx, std::string &VarStr); void addNewTmpVariable(clang::ASTContext &ASTCtx); bool isInvalidOperator(const clang::CXXOperatorCallExpr *OpE); void setTmpVarName(std::string &Name) { TmpVarName = Name; } std::string getTmpVarName(void) { return TmpVarName; } void getVarStrForTemplateSpecialization( std::string &VarStr, const clang::TemplateSpecializationType *TST); void getNewTmpVariable(const clang::QualType &QT, std::string &VarStr); void getNewIntTmpVariable(std::string &VarStr); void getNewAutoTmpVariable(std::string &VarStr); clang::SmallVector CallExprQueue; clang::SmallVector ValidCallExprs; RNFCollectionVisitor *NestedInvocationVisitor; RNFStatementVisitor *StmtVisitor; TransNameQueryWrap *NameQueryWrap; clang::FunctionDecl *TheFuncDecl; clang::Stmt *TheStmt; clang::CallExpr *TheCallExpr; std::string TmpVarName; bool NeedParen; // Unimplemented RemoveNestedFunction(void); RemoveNestedFunction(const RemoveNestedFunction &); void operator=(const RemoveNestedFunction &); }; #endif cvise-2.3.0/clang_delta/RemovePointer.cpp000066400000000000000000000113351402162750500203710ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemovePointer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Only reduce the level of a pointer var if this pointer is \ not referenced or dereferenced except being used as an operand of \ a comparison operator where another operand is 0. We only change \ the definition of this pointer. \n"; static RegisterTransformation Trans("remove-pointer", DescriptionMsg); class RemovePointerCollectionVisitor : public RecursiveASTVisitor { public: explicit RemovePointerCollectionVisitor(RemovePointer *Instance) : ConsumerInstance(Instance), CurrDeclRefExpr(NULL) { } bool VisitVarDecl(VarDecl *VD); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitBinaryOperator(BinaryOperator *BO); private: RemovePointer *ConsumerInstance; const DeclRefExpr *CurrDeclRefExpr; }; bool RemovePointerCollectionVisitor::VisitVarDecl(VarDecl *VD) { ConsumerInstance->handleOneVarDecl(VD); return true; } bool RemovePointerCollectionVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { if (CurrDeclRefExpr != DRE) ConsumerInstance->invalidateOneVarDecl(DRE); CurrDeclRefExpr = NULL; return true; } bool RemovePointerCollectionVisitor::VisitBinaryOperator(BinaryOperator *BO) { if (!BO->isComparisonOp()) return true; const Expr *E = NULL; if (dyn_cast(BO->getLHS()->IgnoreParenCasts())) { E = BO->getRHS()->IgnoreParenCasts(); } else if (dyn_cast(BO->getRHS()->IgnoreParenCasts())) { E = BO->getLHS()->IgnoreParenCasts(); } if (!E) return true; const DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return true; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD || dyn_cast(VD)) return true; if (ConsumerInstance->AllPointerVarDecls.count(VD) && !(ConsumerInstance->AllInvalidPointerVarDecls.count(VD))) CurrDeclRefExpr = DRE; return true; } void RemovePointer::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemovePointerCollectionVisitor(this); } void RemovePointer::HandleTranslationUnit(ASTContext &Ctx) { TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheVarDecl && "NULL TheVarDecl!"); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemovePointer::doAnalysis(void) { for (VarDeclSetVector::iterator I = AllPointerVarDecls.begin(), E = AllPointerVarDecls.end(); I != E; ++I) { const VarDecl *VD = (*I); if (AllInvalidPointerVarDecls.count(VD)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) TheVarDecl = VD; } } void RemovePointer::doRewriting(void) { const VarDecl *FirstVD = TheVarDecl->getCanonicalDecl(); for(VarDecl::redecl_iterator RI = FirstVD->redecls_begin(), RE = FirstVD->redecls_end(); RI != RE; ++RI) { RewriteHelper->removeAStarBefore(*RI); } } void RemovePointer::invalidateOneVarDecl(const DeclRefExpr *DRE) { const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD || dyn_cast(VD)) return; const Type *Ty = VD->getType().getTypePtr(); if (!Ty->isPointerType()) return; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); AllInvalidPointerVarDecls.insert(CanonicalVD); } void RemovePointer::handleOneVarDecl(const VarDecl *VD) { if (isInIncludedFile(VD)) return; if (dyn_cast(VD)) return; if (VD->getAnyInitializer()) return; const Type *Ty = VD->getType().getTypePtr(); if (!Ty->isPointerType()) return; AllPointerVarDecls.insert(VD->getCanonicalDecl()); } RemovePointer::~RemovePointer(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/RemovePointer.h000066400000000000000000000032371402162750500200400ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_POINTER_H #define REMOVE_POINTER_H #include #include "Transformation.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; class DeclRefExpr; } class RemovePointerCollectionVisitor; class RemovePointer : public Transformation { friend class RemovePointerCollectionVisitor; public: RemovePointer(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheVarDecl(NULL) { } ~RemovePointer(void); private: typedef llvm::SmallPtrSet VarDeclSet; typedef llvm::SetVector VarDeclSetVector; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doAnalysis(void); void doRewriting(void); void handleOneVarDecl(const clang::VarDecl *VD); void invalidateOneVarDecl(const clang::DeclRefExpr *DRE); VarDeclSetVector AllPointerVarDecls; VarDeclSet AllInvalidPointerVarDecls; RemovePointerCollectionVisitor *CollectionVisitor; const clang::VarDecl *TheVarDecl; // Unimplemented RemovePointer(void); RemovePointer(const RemovePointer &); void operator=(const RemovePointer &); }; #endif cvise-2.3.0/clang_delta/RemoveTrivialBaseTemplate.cpp000066400000000000000000000110501402162750500226440ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveTrivialBaseTemplate.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass removes a base class if it is an instantiation from a class \ template which doesn't have definition. \n"; static RegisterTransformation Trans("remove-trivial-base-template", DescriptionMsg); class RemoveTrivialBaseTemplateBaseVisitor : public RecursiveASTVisitor { public: explicit RemoveTrivialBaseTemplateBaseVisitor( RemoveTrivialBaseTemplate *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: RemoveTrivialBaseTemplate *ConsumerInstance; }; bool RemoveTrivialBaseTemplateBaseVisitor::VisitCXXRecordDecl( CXXRecordDecl *CXXRD) { ConsumerInstance->handleOneCXXRecordDecl(CXXRD); return true; } void RemoveTrivialBaseTemplate::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveTrivialBaseTemplateBaseVisitor(this); } void RemoveTrivialBaseTemplate::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheDerivedClass && "TheDerivedClass is NULL!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); removeBaseSpecifier(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveTrivialBaseTemplate::handleOneCXXRecordDecl( const CXXRecordDecl *CXXRD) { if (isInIncludedFile(CXXRD) || isSpecialRecordDecl(CXXRD) || !CXXRD->hasDefinition()) return; const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (VisitedCXXRecordDecls.count(CanonicalRD)) return; VisitedCXXRecordDecls.insert(CanonicalRD); unsigned Idx = 0; for (CXXRecordDecl::base_class_const_iterator I = CanonicalRD->bases_begin(), E = CanonicalRD->bases_end(); I != E; ++I, ++Idx) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); if (!Base || getNumExplicitDecls(Base)) { continue; } const ClassTemplateDecl *TmplD = Base->getDescribedClassTemplate(); if (!TmplD) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheDerivedClass = CanonicalRD; ThePos = Idx; } } } void RemoveTrivialBaseTemplate::removeBaseSpecifier(void) { unsigned NumBases = TheDerivedClass->getNumBases(); TransAssert((NumBases >= 1) && "TheDerivedClass doesn't have any base!"); if (NumBases == 1) { SourceLocation StartLoc = TheDerivedClass->getLocation(); StartLoc = RewriteHelper->getLocationUntil(StartLoc, ':'); SourceLocation EndLoc = RewriteHelper->getLocationUntil(StartLoc, '{'); EndLoc = EndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); return; } TransAssert((ThePos < NumBases) && "Invalid ThePos for the base specifier!"); CXXRecordDecl::base_class_const_iterator I = TheDerivedClass->bases_begin(); if (ThePos == 0) { RewriteHelper->removeTextUntil((*I).getSourceRange(), ','); return; } ++I; CXXRecordDecl::base_class_const_iterator E = TheDerivedClass->bases_end(); unsigned Idx = 1; for (; I != E; ++I, ++Idx) { if (Idx == ThePos) { SourceRange Range = (*I).getSourceRange(); SourceLocation EndLoc = RewriteHelper->getEndLocationFromBegin(Range); RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc); return; } } TransAssert(0 && "Unreachable code!"); } RemoveTrivialBaseTemplate::~RemoveTrivialBaseTemplate(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/RemoveTrivialBaseTemplate.h000066400000000000000000000032151402162750500223150ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_TRIVIAL_BASE_TEMPLATE_H #define REMOVE_TRIVIAL_BASE_TEMPLATE_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXBaseSpecifier; class ClassTemplateDecl; } class RemoveTrivialBaseTemplateBaseVisitor; class RemoveTrivialBaseTemplate : public Transformation { friend class RemoveTrivialBaseTemplateBaseVisitor; public: RemoveTrivialBaseTemplate(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheDerivedClass(NULL), ThePos(0) { } ~RemoveTrivialBaseTemplate(void); private: typedef llvm::SmallPtrSet CXXRecordDeclSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneCXXRecordDecl(const clang::CXXRecordDecl *CXXRD); void removeBaseSpecifier(void); CXXRecordDeclSet VisitedCXXRecordDecls; RemoveTrivialBaseTemplateBaseVisitor *CollectionVisitor; const clang::CXXRecordDecl *TheDerivedClass; unsigned ThePos; // Unimplemented RemoveTrivialBaseTemplate(void); RemoveTrivialBaseTemplate(const RemoveTrivialBaseTemplate &); void operator=(const RemoveTrivialBaseTemplate &); }; #endif cvise-2.3.0/clang_delta/RemoveTryCatch.cpp000066400000000000000000000066721402162750500205020ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015 The University of Utah // Copyright (c) 2012 Konstantin Tokarev // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveTryCatch.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove catch blocks and if not present the try block as well. \n"; static RegisterTransformation Trans("remove-try-catch", DescriptionMsg); class RemoveTryCatchAnalysisVisitor : public RecursiveASTVisitor { public: explicit RemoveTryCatchAnalysisVisitor(RemoveTryCatch *Instance) : ConsumerInstance(Instance) { } bool VisitCXXTryStmt(CXXTryStmt *CTS); private: RemoveTryCatch *ConsumerInstance; }; bool RemoveTryCatchAnalysisVisitor::VisitCXXTryStmt( CXXTryStmt *CTS) { if (ConsumerInstance->isInIncludedFile(CTS)) { return true; } // Count try block ++ConsumerInstance->ValidInstanceNum; if (ConsumerInstance->TransformationCounter == ConsumerInstance->ValidInstanceNum) { ConsumerInstance->TheTryCatchStmt = CTS; } int TmpInstanceNum = ConsumerInstance->ValidInstanceNum; // Count all catch blocks ConsumerInstance->ValidInstanceNum += CTS->getNumHandlers(); // Early exit if the transformation counter is less than the index of any // catch block if (ConsumerInstance->TransformationCounter <= TmpInstanceNum) { return true; } // Early exit if the transformation counter is higher than the index of any // catch block if (ConsumerInstance->TransformationCounter > ConsumerInstance->ValidInstanceNum) { return true; } TransAssert(ConsumerInstance->TransformationCounter > TmpInstanceNum); int CatchIdx = ConsumerInstance->TransformationCounter - TmpInstanceNum - 1; ConsumerInstance->TheTryCatchStmt = CTS->getHandler(CatchIdx); // If the last catch block is removed the "try" has to be removed as well if (CTS->getNumHandlers() == 1) { ConsumerInstance->RewriteTryStmt = CTS; } return true; } void RemoveTryCatch::Initialize(ASTContext &context) { Transformation::Initialize(context); AnalysisVisitor = new RemoveTryCatchAnalysisVisitor(this); } void RemoveTryCatch::HandleTranslationUnit(ASTContext &Ctx) { AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheTryCatchStmt && "NULL TheTryCatchStmt!"); removeStmt(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveTryCatch::removeStmt() { SourceRange Range = TheTryCatchStmt->getSourceRange(); TheRewriter.RemoveText(Range); if (RewriteTryStmt != nullptr) { TheRewriter.RemoveText(RewriteTryStmt->getBeginLoc(), 3); } } RemoveTryCatch::~RemoveTryCatch() { delete AnalysisVisitor; } cvise-2.3.0/clang_delta/RemoveTryCatch.h000066400000000000000000000024641402162750500201420ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // Copyright (c) 2012 Konstantin Tokarev // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_TRY_CATCH_H #define REMOVE_TRY_CATCH_H #include #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class Stmt; } class RemoveTryCatchAnalysisVisitor; class RemoveTryCatch : public Transformation { friend class RemoveTryCatchAnalysisVisitor; public: RemoveTryCatch(const char *TransName, const char *Desc) : Transformation(TransName, Desc), AnalysisVisitor(0), RewriteTryStmt(0), TheTryCatchStmt(0) { } ~RemoveTryCatch(); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void removeStmt(); RemoveTryCatchAnalysisVisitor *AnalysisVisitor; clang::Stmt *RewriteTryStmt; clang::Stmt *TheTryCatchStmt; // Unimplemented RemoveTryCatch(); RemoveTryCatch(const RemoveTryCatch &); void operator=(const RemoveTryCatch &); }; #endif cvise-2.3.0/clang_delta/RemoveUnresolvedBase.cpp000066400000000000000000000103641402162750500216730ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveUnresolvedBase.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass tries to remove a base specifier if we cannot \ resolve it. \n"; static RegisterTransformation Trans("remove-unresolved-base", DescriptionMsg); class RemoveUnresolvedBaseASTVisitor : public RecursiveASTVisitor { public: explicit RemoveUnresolvedBaseASTVisitor(RemoveUnresolvedBase *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: RemoveUnresolvedBase *ConsumerInstance; }; bool RemoveUnresolvedBaseASTVisitor::VisitCXXRecordDecl(CXXRecordDecl *CXXRD) { if (ConsumerInstance->isInIncludedFile(CXXRD) || !CXXRD->hasDefinition()) return true; const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (ConsumerInstance->VisitedCXXRecordDecls.count(CanonicalRD)) return true; ConsumerInstance->VisitedCXXRecordDecls.insert(CanonicalRD); unsigned Idx = 0; for (CXXRecordDecl::base_class_const_iterator I = CanonicalRD->bases_begin(), E = CanonicalRD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = ConsumerInstance->getBaseDeclFromType(Ty); if (Base) { Idx++; continue; } ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheDerivedClass = CanonicalRD; ConsumerInstance->TheBaseSpecifier = BS; ConsumerInstance->TheIndex = Idx; } Idx++; } return true; } void RemoveUnresolvedBase::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveUnresolvedBaseASTVisitor(this); } void RemoveUnresolvedBase::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheDerivedClass && "NULL TheDerivedClass!"); TransAssert(TheBaseSpecifier && "NULL TheBaseSpecifier!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); removeBaseSpecifier(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveUnresolvedBase::removeBaseSpecifier(void) { unsigned NumBases = TheDerivedClass->getNumBases(); TransAssert((NumBases >= 1) && "TheDerivedClass doesn't have any base!"); CXXRecordDecl::base_class_const_iterator I = TheDerivedClass->bases_begin(); if (NumBases == 1) { TransAssert((TheIndex == 0) && "Invalid Index for the base specifier!"); TransAssert((I == TheBaseSpecifier) && "Unmatched base specifier!"); (void)I; SourceLocation StartLoc = TheDerivedClass->getLocation(); StartLoc = RewriteHelper->getLocationUntil(StartLoc, ':'); SourceLocation EndLoc = RewriteHelper->getLocationUntil(StartLoc, '{'); EndLoc = EndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); return; } SourceRange Range = TheBaseSpecifier->getSourceRange(); if (TheIndex == 0) { RewriteHelper->removeTextUntil(Range, ','); } else { SourceLocation EndLoc = RewriteHelper->getEndLocationFromBegin(Range); RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc); } } RemoveUnresolvedBase::~RemoveUnresolvedBase(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/RemoveUnresolvedBase.h000066400000000000000000000031321402162750500213330ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNRESOLVED_BASE_H #define REMOVE_UNRESOLVED_BASE_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXBaseSpecifier; class CXXRecordDecl; } class RemoveUnresolvedBaseASTVisitor; class RemoveUnresolvedBase : public Transformation { friend class RemoveUnresolvedBaseASTVisitor; public: RemoveUnresolvedBase(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheDerivedClass(NULL), TheBaseSpecifier(NULL), TheIndex(0) { } ~RemoveUnresolvedBase(void); private: typedef llvm::SmallPtrSet CXXRecordDeclSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void removeBaseSpecifier(void); CXXRecordDeclSet VisitedCXXRecordDecls; RemoveUnresolvedBaseASTVisitor *CollectionVisitor; const clang::CXXRecordDecl *TheDerivedClass; const clang::CXXBaseSpecifier *TheBaseSpecifier; unsigned TheIndex; // Unimplemented RemoveUnresolvedBase(void); RemoveUnresolvedBase(const RemoveUnresolvedBase &); void operator=(const RemoveUnresolvedBase &); }; #endif cvise-2.3.0/clang_delta/RemoveUnusedEnumMember.cpp000066400000000000000000000072771402162750500222030ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2019, 2020 The University of Utah // Copyright (c) 2012 Konstantin Tokarev // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveUnusedEnumMember.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove unused enum member declarations. \n"; static RegisterTransformation Trans("remove-unused-enum-member", DescriptionMsg); class RemoveUnusedEnumMemberAnalysisVisitor : public RecursiveASTVisitor { public: explicit RemoveUnusedEnumMemberAnalysisVisitor( RemoveUnusedEnumMember *Instance) : ConsumerInstance(Instance) { } bool VisitEnumDecl(EnumDecl *ED); private: RemoveUnusedEnumMember *ConsumerInstance; }; bool RemoveUnusedEnumMemberAnalysisVisitor::VisitEnumDecl(EnumDecl *ED) { if (ConsumerInstance->isInIncludedFile(ED) || ED != ED->getCanonicalDecl()) return true; /* Make it backward compatible where --to-counter is unset. */ if (ConsumerInstance->ToCounter == -1) ConsumerInstance->ToCounter = ConsumerInstance->TransformationCounter; for (EnumDecl::enumerator_iterator I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) { if (!(*I)->isReferenced()) { ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum >= ConsumerInstance->TransformationCounter && ConsumerInstance->ValidInstanceNum <= ConsumerInstance->ToCounter) ConsumerInstance->EnumValues.push_back (I); } } return true; } void RemoveUnusedEnumMember::Initialize(ASTContext &context) { Transformation::Initialize(context); AnalysisVisitor = new RemoveUnusedEnumMemberAnalysisVisitor(this); } void RemoveUnusedEnumMember::HandleTranslationUnit(ASTContext &Ctx) { AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } if (ToCounter != -1 && ToCounter > ValidInstanceNum) { TransError = TransToCounterTooBigError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); for (auto ev : EnumValues) { removeEnumConstantDecl(ev); } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveUnusedEnumMember::removeEnumConstantDecl(clang::EnumDecl::enumerator_iterator it) { SourceLocation StartLoc = it->getBeginLoc(); if (StartLoc.isMacroID()) { CharSourceRange Range = SrcManager->getExpansionRange(StartLoc); StartLoc = Range.getBegin(); } SourceLocation EndLoc = it->getEndLoc(); if (EndLoc.isMacroID()) { CharSourceRange Range = SrcManager->getExpansionRange(EndLoc); EndLoc = Range.getEnd(); } SourceLocation CommaLoc = Lexer::findLocationAfterToken( EndLoc, tok::comma, *SrcManager, Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/false); if (CommaLoc.isValid()) EndLoc = CommaLoc; TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); } RemoveUnusedEnumMember::~RemoveUnusedEnumMember() { delete AnalysisVisitor; } cvise-2.3.0/clang_delta/RemoveUnusedEnumMember.h000066400000000000000000000027121402162750500216350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2015, 2018 The University of Utah // Copyright (c) 2012 Konstantin Tokarev // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNUSED_ENUM_MEMBER_H #define REMOVE_UNUSED_ENUM_MEMBER_H #include #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" #include "Transformation.h" class RemoveUnusedEnumMemberAnalysisVisitor; class RemoveUnusedEnumMember : public Transformation { friend class RemoveUnusedEnumMemberAnalysisVisitor; public: RemoveUnusedEnumMember(const char *TransName, const char *Desc) : Transformation(TransName, Desc, /*MultipleRewrites*/true), AnalysisVisitor(0), EnumValues() { } ~RemoveUnusedEnumMember(); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void removeEnumConstantDecl(clang::EnumDecl::enumerator_iterator it); RemoveUnusedEnumMemberAnalysisVisitor *AnalysisVisitor; std::vector EnumValues; // Unimplemented RemoveUnusedEnumMember(); RemoveUnusedEnumMember(const RemoveUnusedEnumMember &); void operator=(const RemoveUnusedEnumMember &); }; #endif cvise-2.3.0/clang_delta/RemoveUnusedFunction.cpp000066400000000000000000001021621402162750500217210ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveUnusedFunction.h" #include #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/Attr.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove unused function declarations. \n"; static RegisterTransformation Trans("remove-unused-function", DescriptionMsg); class RUFAnalysisVisitor : public RecursiveASTVisitor { public: explicit RUFAnalysisVisitor(RemoveUnusedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: RemoveUnusedFunction *ConsumerInstance; }; typedef llvm::DenseMap UsingFunctionDeclsMap; typedef llvm::SmallPtrSet FunctionDeclsSet; typedef llvm::SmallPtrSet MemberSpecializationSet; namespace { class UsingDeclVisitor : public RecursiveASTVisitor { public: UsingDeclVisitor(const FunctionDecl *FD, RemoveUnusedFunction *Instance) : CurrentFD(FD), ConsumerInstance(Instance) { } bool VisitUsingDecl(UsingDecl *D); private: const FunctionDecl *CurrentFD; RemoveUnusedFunction *ConsumerInstance; }; bool UsingDeclVisitor::VisitUsingDecl(UsingDecl *D) { ConsumerInstance->handleOneUsingDecl(CurrentFD, D); return true; } // end of UsingDeclVisitor class SpecializationVisitor : public RecursiveASTVisitor { public: explicit SpecializationVisitor(RemoveUnusedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitMemberExpr(MemberExpr *E); bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); bool VisitCallExpr(CallExpr *E); bool shouldVisitTemplateInstantiations() { return true; } private: RemoveUnusedFunction *ConsumerInstance; }; bool SpecializationVisitor::VisitFunctionDecl(FunctionDecl *FD) { ConsumerInstance->handleOneFunctionDecl(FD); return true; } bool SpecializationVisitor::VisitMemberExpr(MemberExpr *E) { ConsumerInstance->handleOneMemberExpr(E); return true; } bool SpecializationVisitor::VisitCXXOperatorCallExpr( CXXOperatorCallExpr *E) { // ConsumerInstance->handleOneCXXOperatorCallExpr(E); return true; } bool SpecializationVisitor::VisitCallExpr( CallExpr *E) { ConsumerInstance->handleOneCallExpr(E); return true; } // end of SpecializationVisitor class ReferencedFunctionDeclVisitor : public RecursiveASTVisitor { public: ReferencedFunctionDeclVisitor(const FunctionDecl *FD, RemoveUnusedFunction *Instance) : CurrentFD(FD), ConsumerInstance(Instance) { } bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); private: const FunctionDecl *CurrentFD; RemoveUnusedFunction *ConsumerInstance; }; bool ReferencedFunctionDeclVisitor::VisitUnresolvedLookupExpr( UnresolvedLookupExpr *E) { ConsumerInstance->handleOneUnresolvedLookupExpr(CurrentFD, E); return true; } bool ReferencedFunctionDeclVisitor::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { ConsumerInstance->handleOneCXXDependentScopeMemberExpr(CurrentFD, E); return true; } } // end of anon namespace class ExtraReferenceVisitorWrapper : public RecursiveASTVisitor { public: explicit ExtraReferenceVisitorWrapper(RemoveUnusedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: RemoveUnusedFunction *ConsumerInstance; }; bool ExtraReferenceVisitorWrapper::VisitFunctionDecl(FunctionDecl *FD) { if (!FD->isThisDeclarationADefinition()) return true; UsingDeclVisitor Visitor(FD, ConsumerInstance); Visitor.TraverseDecl(FD); ReferencedFunctionDeclVisitor FuncVisitor(FD, ConsumerInstance); FuncVisitor.TraverseDecl(FD); ConsumerInstance->setInlinedSystemFunctions(FD); return true; } bool RUFAnalysisVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD)) return true; const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (ConsumerInstance->VisitedFDs.count(CanonicalFD)) return true; ConsumerInstance->VisitedFDs.insert(CanonicalFD); FunctionDecl::TemplatedKind TK = FD->getTemplatedKind(); if (TK == FunctionDecl::TK_MemberSpecialization) { const FunctionDecl *Member = FD->getInstantiatedFromMemberFunction(); ConsumerInstance->addOneMemberSpecialization(FD, Member); return true; } else if (TK == FunctionDecl::TK_DependentFunctionTemplateSpecialization) { const DependentFunctionTemplateSpecializationInfo *Info = FD->getDependentSpecializationInfo(); // don't need to track all specs, just associate FD with one // of those if (Info->getNumTemplates() > 0) { const FunctionDecl *Member = Info->getTemplate(0)->getTemplatedDecl(); ConsumerInstance->addOneMemberSpecialization(FD, Member); } return true; } TemplateSpecializationKind K = FD->getTemplateSpecializationKind(); if (K == TSK_ExplicitSpecialization) { ConsumerInstance->addFuncToExplicitSpecs(FD); return true; } // Why implicit instantiation would appear here? e.g.: // template void foo(T &); // struct S { friend void foo<>(bool&); }; // OK, just add it into MemberSpec set. if (K == TSK_ImplicitInstantiation) { const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate(); TransAssert(FTD && "NULL FunctionTemplateDecl!"); const FunctionDecl *Member = FTD->getTemplatedDecl(); ConsumerInstance->addOneMemberSpecialization(FD, Member); return true; } if (FD->isReferenced() || FD->isMain() || FD->hasAttr() || ConsumerInstance->hasReferencedSpecialization(CanonicalFD) || ConsumerInstance->isInlinedSystemFunction(CanonicalFD) || ConsumerInstance->isInReferencedSet(CanonicalFD) || !ConsumerInstance->hasAtLeastOneValidLocation(CanonicalFD)) return true; ConsumerInstance->addOneFunctionDecl(CanonicalFD); return true; } void RemoveUnusedFunction::Initialize(ASTContext &context) { Transformation::Initialize(context); AnalysisVisitor = new RUFAnalysisVisitor(this); VisitorWrapper = new ExtraReferenceVisitorWrapper(this); initializeInlinedSystemFunctions(); } void RemoveUnusedFunction::HandleTranslationUnit(ASTContext &Ctx) { VisitorWrapper->TraverseDecl(Ctx.getTranslationUnitDecl()); // visit using decls declared outsided function-scope UsingDeclVisitor Visitor(NULL, this); Visitor.TraverseDecl(Ctx.getTranslationUnitDecl()); SpecializationVisitor SpecVisitor(this); SpecVisitor.TraverseDecl(Ctx.getTranslationUnitDecl()); AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (!checkCounterValidity()) return; Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } // Each "key" function is inlined into the corresponding "value" // function, and its isReferenced flag is false... void RemoveUnusedFunction::initializeInlinedSystemFunctions() { InlinedSystemFunctions["__fprintf_chk"] = "fprintf"; InlinedSystemFunctions["__printf_chk"] = "printf"; InlinedSystemFunctions["__dprintf_chk"] = "dprintf"; InlinedSystemFunctions["__asprintf_chk"] = "asprintf"; InlinedSystemFunctions["__obstack_printf_chk"] = "obstack_printf"; InlinedSystemFunctions["__swprintf_chk"] = "swprintf"; InlinedSystemFunctions["__swprintf_alias"] = "swprintf"; InlinedSystemFunctions["__fwprintf_chk"] = "fwprintf"; InlinedSystemFunctions["__wprintf_chk"] = "wprintf"; } void RemoveUnusedFunction::doRewriting() { if (ToCounter <= 0) { TransAssert(TheFunctionDecl && "NULL TheFunctionDecl!"); // add FD under removal first in order to avoid recursion, e.g. // void foo() { using ::foo; } RemovedFDs.insert(TheFunctionDecl); removeOneFunctionDeclGroup(TheFunctionDecl); return; } TransAssert((TransformationCounter <= static_cast(AllValidFunctionDecls.size())) && "TransformationCounter is larger than the number of defs!"); TransAssert((ToCounter <= static_cast(AllValidFunctionDecls.size())) && "ToCounter is larger than the number of defs!"); for (int I = ToCounter; I >= TransformationCounter; --I) { TransAssert((I >= 1) && "Invalid Index!"); const FunctionDecl *FD = AllValidFunctionDecls[I-1]; TransAssert(FD && "NULL FunctionDecl!"); RemovedFDs.insert(FD); removeOneFunctionDeclGroup(FD); } } SourceLocation RemoveUnusedFunction::getExtensionLocStart( SourceLocation Loc) { SourceLocation StartLoc = Loc; FileID FID = SrcManager->getMainFileID(); SourceLocation FileStartLoc = SrcManager->getLocForStartOfFile(FID); const char * const FileStartBuf = SrcManager->getCharacterData(FileStartLoc); const char *StartBuf = SrcManager->getCharacterData(StartLoc); const char *MatchedPos = NULL; bool Out = false; std::string Ext = "__noisnetxe__"; while (true) { do { StartBuf--; if (StartBuf < FileStartBuf) break; } while (isspace(*StartBuf)); int Len = static_cast(Ext.length()); for (int I = 0; I < Len; I++) { if (StartBuf < FileStartBuf || *StartBuf != Ext[I]) { Out = true; break; } StartBuf--; } if (Out) break; StartBuf++; MatchedPos = StartBuf; } // no __extension__ in front if (MatchedPos == NULL) return Loc; TransAssert((MatchedPos >= FileStartBuf) && "Invalid MatchedPos!"); std::string ExtStr(MatchedPos, Ext.length()); TransAssert((ExtStr == "__extension__") && "Invalid ExtStr!"); (void)ExtStr; int Offset = MatchedPos - (SrcManager->getCharacterData(StartLoc)); return StartLoc.getLocWithOffset(Offset); } bool RemoveUnusedFunction::hasValidOuterLocStart( const FunctionTemplateDecl *FTD, const FunctionDecl *FD) { SourceLocation FTDLocStart = FTD->getSourceRange().getBegin(); SourceLocation FDLocStart = FD->getSourceRange().getBegin(); const char *FTDStartPos = SrcManager->getCharacterData(FTDLocStart); const char *FDStartPos = SrcManager->getCharacterData(FDLocStart); return (FTDStartPos < FDStartPos); } SourceLocation RemoveUnusedFunction::getFunctionOuterLocStart( const FunctionDecl *FD) { SourceLocation LocStart = FD->getBeginLoc(); bool RecordLoc = false; // check if FD is from a function template if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) { // get FTD->getBeginLoc() only if it is less than FD->getBeginLoc, // for example, in the code below: // template struct S {template void foo();}; // template template void S::foo() { } // where // FTD->getBeginLoc() points to the begining of "template" if (hasValidOuterLocStart(FTD, FD)) { LocStart = FTD->getBeginLoc(); RecordLoc = true; } } if (LocStart.isMacroID()) LocStart = SrcManager->getExpansionLoc(LocStart); // this is ugly, but how do we get the location of __extension__? e.g.: // __extension__ void foo(); LocStart = getExtensionLocStart(LocStart); // In some cases where the given input is not well-formed, we may // end up with duplicate locations for the FunctionTemplateDecl // case. In such cases, we simply return an invalid SourceLocation, // which will ben skipped by the caller of getFunctionOuterLocStart. if (RecordLoc) { if (VisitedLocations.count(LocStart)) return SourceLocation(); VisitedLocations.insert(LocStart); } return LocStart; } bool RemoveUnusedFunction::isTokenOperator(SourceLocation Loc) { const char * Buf = SrcManager->getCharacterData(Loc); std::string OStr = "operator"; std::string S(Buf, OStr.length()); return (S == OStr); } // this is ugly, but seems clang gives "bad" location for the code below: // template void foo(T *); // template struct S { // template friend void foo(T1 *); // ^ FD.end_loc points here // }; // template struct S; SourceLocation RemoveUnusedFunction::getFunctionLocEnd( SourceLocation LocStart, SourceLocation LocEnd, const FunctionDecl *FD) { if (!FD->getDescribedFunctionTemplate()) { // Remove trailing ; if function has no body if (!FD->hasBody()) { return RewriteHelper->getLocationUntil(LocEnd, ';'); } else { return LocEnd; } } SourceLocation FDLoc = FD->getLocation(); if (FDLoc.isMacroID()) FDLoc = SrcManager->getExpansionLoc(FDLoc); const char * const FDBuf = SrcManager->getCharacterData(FDLoc); const char * LocEndBuf = SrcManager->getCharacterData(LocEnd); if ((FDBuf < LocEndBuf) && !isTokenOperator(FDLoc) && !FD->isDeleted() && !FD->isDefaulted()) return LocEnd; int Offset = 0; while (*LocEndBuf != ';') { LocEndBuf++; Offset++; } return LocEnd.getLocWithOffset(Offset-1); } void RemoveUnusedFunction::removeOneFunctionDecl(const FunctionDecl *FD) { SourceRange FuncRange = FD->getSourceRange(); SourceLocation LocEnd = FuncRange.getEnd(); if (LocEnd.isMacroID()) LocEnd = SrcManager->getExpansionLoc(LocEnd); if (!FD->isInExternCContext() && !FD->isInExternCXXContext()) { SourceLocation FuncLocStart = getFunctionOuterLocStart(FD); if (FuncLocStart.isInvalid()) return; LocEnd = getFunctionLocEnd(FuncLocStart, LocEnd, FD); if (SrcManager->isWrittenInMainFile(FuncLocStart) && SrcManager->isWrittenInMainFile(LocEnd)) TheRewriter.RemoveText(SourceRange(FuncLocStart, LocEnd)); return; } const DeclContext *Ctx = FD->getLookupParent(); const LinkageSpecDecl *Linkage = dyn_cast(Ctx); if (!Linkage) { SourceLocation FuncLocStart = getFunctionOuterLocStart(FD); if (FuncLocStart.isInvalid()) return; LocEnd = getFunctionLocEnd(FuncLocStart, LocEnd, FD); TheRewriter.RemoveText(SourceRange(FuncLocStart, LocEnd)); return; } // cases like: // extern "C++" { void foo(); } // namespace { using ::foo; } if (Linkage->hasBraces()) { SourceLocation FuncLocStart = getFunctionOuterLocStart(FD); if (FuncLocStart.isInvalid()) return; TheRewriter.RemoveText(SourceRange(FuncLocStart, LocEnd)); return; } // cases like: // extern "C++" void foo(); // it also handles cases such as extern "C++" template ... SourceLocation LocStart = Linkage->getExternLoc(); if (LocStart.isMacroID()) LocStart = SrcManager->getExpansionLoc(LocStart); LocStart = getExtensionLocStart(LocStart); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); } void RemoveUnusedFunction::removeOneExplicitInstantiation( const FunctionDecl *Spec) { FileID FID = SrcManager->getMainFileID(); SourceLocation FileStartLoc = SrcManager->getLocForStartOfFile(FID); const char * const FileStartBuf = SrcManager->getCharacterData(FileStartLoc); SourceLocation Loc = Spec->getPointOfInstantiation(); if (Loc.isInvalid()) { TheRewriter.RemoveText(Spec->getSourceRange()); return; } const char *OrigStartBuf = SrcManager->getCharacterData(Loc); const char *StartBuf = OrigStartBuf; int Offset = 0; while ((*StartBuf != ';') && (*StartBuf != '{') && (*StartBuf != '}') && (StartBuf >= FileStartBuf)) { StartBuf--; Offset--; } SourceLocation LocStart = Loc.getLocWithOffset(Offset + 1); Offset = 0; StartBuf = OrigStartBuf; while (*StartBuf != ';') { StartBuf++; Offset++; } SourceLocation LocEnd = Loc.getLocWithOffset(Offset - 1); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); } void RemoveUnusedFunction::removeRemainingExplicitSpecs( MemberSpecializationSet *ExplicitSpecs) { if (!ExplicitSpecs) return; for (MemberSpecializationSet::iterator I = ExplicitSpecs->begin(), E = ExplicitSpecs->end(); I != E; ++I) { removeOneFunctionDecl(*I); } } // We can't handle function template explicit instantiation because // I am not sure how to analyze its source location. // For example, in the code below: // template bool foo(const int&) {return true;} // template bool foo(const int&); // ^ point of instantiation // What I could get is the point of the instantiation, but I // don't know the source range for the entire instantiation declaration. void RemoveUnusedFunction::removeFunctionExplicitInstantiations( const FunctionDecl *FD) { const FunctionTemplateDecl *FTD = getTopDescribedTemplate(FD); if (!FTD) return; const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); MemberSpecializationSet *S = MemberToInstantiations[CanonicalFD]; MemberSpecializationSet *ExplicitSpecs = FuncToExplicitSpecs[CanonicalFD]; for (FunctionTemplateDecl::spec_iterator I = FTD->spec_begin(), E = FTD->spec_end(); I != E; ++I) { FunctionDecl *Spec = (*I); TemplateSpecializationKind K = Spec->getTemplateSpecializationKind(); if (K == TSK_ExplicitSpecialization) { // check if the explicit spec points to any dependent specs, // skip it if yes if (!ExplicitSpecs) { removeOneFunctionDecl(Spec); } else if (ExplicitSpecs->count(Spec)) { removeOneFunctionDecl(Spec); ExplicitSpecs->erase(Spec); } continue; } if (K != TSK_ExplicitInstantiationDeclaration && K != TSK_ExplicitInstantiationDefinition) continue; TransAssert(!Spec->isReferenced() && "Referenced Instantiation!"); removeOneExplicitInstantiation(Spec); if (S && S->count(Spec)) { S->erase(Spec); } } removeRemainingExplicitSpecs(ExplicitSpecs); if (!S) return; for (MemberSpecializationSet::iterator I = S->begin(), E = S->end(); I != E; ++I) { const FunctionDecl *Spec = (*I); TemplateSpecializationKind K = Spec->getTemplateSpecializationKind(); TransAssert(((K == TSK_ExplicitInstantiationDeclaration) || (K == TSK_ExplicitInstantiationDefinition)) && "Bad Instantiation!"); (void)K; removeOneExplicitInstantiation(Spec); } } void RemoveUnusedFunction::removeMemberSpecializations(const FunctionDecl *FD) { MemberSpecializationSet *S = MemberToSpecs[FD->getCanonicalDecl()]; if (!S) return; for (MemberSpecializationSet::iterator I = S->begin(), E = S->end(); I != E; ++I) { const FunctionDecl *Spec = (*I); removeOneFunctionDecl(Spec); } } void RemoveUnusedFunction::removeOneFunctionDeclGroup(const FunctionDecl *FD) { for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(), RE = FD->redecls_end(); RI != RE; ++RI) { removeOneFunctionDecl(*RI); } removeMemberSpecializations(FD); removeFunctionExplicitInstantiations(FD); for (UsingFunctionDeclsMap::const_iterator I = UsingFDs.begin(), E = UsingFDs.end(); I != E; ++I) { if ((*I).second != FD) continue; const FunctionDecl *ParentFD = UsingParentFDs[(*I).first]; if (ParentFD && RemovedFDs.count(ParentFD->getCanonicalDecl())) continue; const UsingDecl *UD = (*I).first; SourceRange Range = UD->getSourceRange(); if (Range.getBegin().isMacroID()) { TheRewriter.RemoveText(SrcManager->getExpansionRange(Range)); } else { RewriteHelper->removeDecl((*I).first); } } } bool RemoveUnusedFunction::hasAtLeastOneValidLocation(const FunctionDecl *FD) { for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(), RE = FD->redecls_end(); RI != RE; ++RI) { SourceRange FuncRange = FD->getSourceRange(); SourceLocation StartLoc = FuncRange.getBegin(); if (StartLoc.isMacroID()) StartLoc = SrcManager->getExpansionLoc(StartLoc); SourceLocation EndLoc = FuncRange.getEnd(); if (EndLoc.isMacroID()) EndLoc = SrcManager->getExpansionLoc(EndLoc); if (SrcManager->isWrittenInMainFile(StartLoc) && SrcManager->isWrittenInMainFile(EndLoc)) return true; } return false; } bool RemoveUnusedFunction::isInReferencedSet(const FunctionDecl *CanonicalFD) { TransAssert(CanonicalFD && "NULL FunctionDecl!"); return ReferencedFDs.count(CanonicalFD); } const FunctionDecl * RemoveUnusedFunction::lookupFunctionDeclShallow(const DeclarationName &DName, const DeclContext *Ctx) { if (dyn_cast(Ctx)) return NULL; DeclContext::lookup_result Result = Ctx->lookup(DName); for (auto I = Result.begin(), E = Result.end(); I != E; ++I) { if (const FunctionDecl *FD = dyn_cast(*I)) return FD; if (const UsingShadowDecl *USD = dyn_cast(*I)) { const NamedDecl *ND = USD->getTargetDecl(); if (const FunctionDecl *FD = dyn_cast(ND)) return FD; } if (const FunctionTemplateDecl *TD = dyn_cast(*I)) { return TD->getTemplatedDecl(); } } bool InNamespace = Ctx->isNamespace(); for (auto *I : Ctx->using_directives()) { const NamespaceDecl *ND = I->getNominatedNamespace(); // avoid infinite recursion if ((InNamespace && dyn_cast(Ctx) == ND) || ND->getLookupParent() == Ctx) { return NULL; } if (const FunctionDecl *FD = lookupFunctionDeclShallow(DName, ND)) return FD; } return NULL; } const FunctionDecl *RemoveUnusedFunction::getFunctionDeclFromSpecifier( const DeclarationName &Name, const NestedNameSpecifier *NNS) { const FunctionDecl *FD = NULL; switch (NNS->getKind()) { case NestedNameSpecifier::Namespace: FD = lookupFunctionDeclShallow(Name, NNS->getAsNamespace()); break; case NestedNameSpecifier::NamespaceAlias: FD = lookupFunctionDeclShallow(Name, NNS->getAsNamespaceAlias()->getNamespace()); break; case NestedNameSpecifier::Global: FD = lookupFunctionDeclShallow(Name, Context->getTranslationUnitDecl()); break; default: return NULL; } return FD; } void RemoveUnusedFunction::handleOneUsingDecl(const FunctionDecl *CurrentFD, const UsingDecl *UD) { if (VisitedUsingDecls.count(UD)) return; VisitedUsingDecls.insert(UD); const NestedNameSpecifier *NNS = UD->getQualifier(); if (!NNS) return; DeclarationName Name = UD->getUnderlyingDecl()->getDeclName(); const FunctionDecl *FD = getFunctionDeclFromSpecifier(Name, NNS); if (!FD || FD->isReferenced()) return; // we don't put FD into ReferencedFD because we will // delete both the FD and the UsingDecl if FD is only referenced // by UsingDecl[s]. const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); TransAssert((UsingFDs.find(UD) == UsingFDs.end()) && "Duplicate UsingDecl to FD map!"); UsingFDs[UD] = CanonicalFD; if (CurrentFD) { TransAssert(CurrentFD->isThisDeclarationADefinition() && "CurrentFD is not a definition!"); TransAssert((UsingParentFDs.find(UD) == UsingParentFDs.end()) && "Duplicate UsingDecl to ParentFD map!"); UsingParentFDs[UD] = CurrentFD; } } void RemoveUnusedFunction::handleOneCXXDependentScopeMemberExpr( const FunctionDecl *CurrentFD, const CXXDependentScopeMemberExpr *E) { if (E->isImplicitAccess()) return; DeclarationName DName = E->getMember(); DeclarationName::NameKind K = DName.getNameKind(); if ((K != DeclarationName::CXXOperatorName) && (K != DeclarationName::Identifier)) return; const Expr *Base = E->getBase()->IgnoreParenCasts(); const FunctionDecl *FD = NULL; if (dyn_cast(Base)) { TransAssert(CurrentFD && "NULL CurrentFD"); const DeclContext *Ctx = CurrentFD->getLookupParent(); TransAssert(Ctx && "Bad DeclContext!"); DeclContextSet VisitedCtxs; FD = lookupFunctionDecl(DName, Ctx, VisitedCtxs); // we may not get FD in cases where we have this->m_field if (FD) addOneReferencedFunction(FD); return; } } void RemoveUnusedFunction::handleOneUnresolvedLookupExpr( const FunctionDecl *CurrentFD, const UnresolvedLookupExpr *E) { DeclarationName DName = E->getName(); DeclarationName::NameKind K = DName.getNameKind(); if ((K != DeclarationName::CXXOperatorName) && (K != DeclarationName::Identifier)) return; const NestedNameSpecifier *NNS = E->getQualifier(); // we fail only if UE is invoked with some qualifier or // instantiation, e.g.: // namespace NS { template void foo(T&) { } } // template void bar(T p) { NS::foo(p); } // removing foo would fail. // // template void foo() { } // template void bar() { foo(); } // removing foo would faill, too // // On the other handle, the following code is ok: // template void foo(T&) { } // template void bar(T p) { foo(p); } const FunctionDecl *FD = NULL; if (NNS) { FD = getFunctionDeclFromSpecifier(DName, NNS); } else { const DeclContext *Ctx = CurrentFD->getLookupParent(); FD = lookupFunctionDeclShallow(DName, Ctx); } if (!FD || FD->isReferenced()) return; addOneReferencedFunction(FD); } void RemoveUnusedFunction::handleOneMemberExpr( const MemberExpr *ME) { const ValueDecl *VD = ME->getMemberDecl(); const CXXMethodDecl *MD = dyn_cast(VD); if (!MD) return; if (const FunctionDecl *FD = MD->getInstantiatedFromMemberFunction()) addOneReferencedFunction(FD); } const FunctionDecl *RemoveUnusedFunction::getSourceFunctionDecl( const FunctionDecl *TheFD) { if (FunctionTemplateDecl *FTD = TheFD->getPrimaryTemplate()) { if (const FunctionTemplateDecl *D = FTD->getInstantiatedFromMemberTemplate()) return D->getTemplatedDecl(); else return FTD->getTemplatedDecl(); } if (const FunctionDecl *FD = TheFD->getInstantiatedFromMemberFunction()) return FD; return TheFD; } // we can't handle cases like below: // template struct S; // template void foo(S); // template<> void foo(S); // template void foo(S); // the second instantiation will refer to the specialization, and thus // we lose the source range of it... in fact, it points to the // original template declaration. void RemoveUnusedFunction::handleOneFunctionDecl(const FunctionDecl *TheFD) { const FunctionDecl *FD = getSourceFunctionDecl(TheFD); if (TheFD->isReferenced()) { addOneReferencedFunction(FD); return; } FunctionDecl::TemplatedKind TK = TheFD->getTemplatedKind(); // Now it's another ugly part, with dependent function template spec, // we lose the explicit specialization in Member's spec_iterator, e.g.: // template void foo(T); // line 1 // template class A { // line 2 // friend void foo<>(T1); // line 3 // }; // line 4 // template <> void foo(char); // line 5 // template class A; // line 6 // In the code above, foo's spec_iterator has an explicit spec, // but this spec's source range points to the dependent_spec at line 3, // and then we will be in trouble... if (TK == FunctionDecl::TK_DependentFunctionTemplateSpecialization) { const DependentFunctionTemplateSpecializationInfo *Info = TheFD->getDependentSpecializationInfo(); // don't need to track all specs, just associate FD with one // of those if (Info->getNumTemplates() > 0) { const FunctionDecl *Member = Info->getTemplate(0)->getTemplatedDecl(); createFuncToExplicitSpecs(Member); } return; } // keep explicit instantiations that are not recored by original // template's spec_iterator, e.g.: // template class S { // public: // template void foo(V& v) {}; // }; // typedef S SS; // template void SS::foo(unsigned short&); FunctionTemplateDecl *FTD = TheFD->getPrimaryTemplate(); if (!FTD) return; const FunctionTemplateDecl *D = FTD->getInstantiatedFromMemberTemplate(); if (!D) return; const FunctionDecl *OrigFD = D->getTemplatedDecl(); TemplateSpecializationKind K = TheFD->getTemplateSpecializationKind(); if (K != TSK_ExplicitInstantiationDeclaration && K != TSK_ExplicitInstantiationDefinition) return; MemberSpecializationSet *S = MemberToInstantiations[OrigFD->getCanonicalDecl()]; if (S == NULL) { S = new MemberSpecializationSet(); MemberToInstantiations[OrigFD->getCanonicalDecl()] = S; } S->insert(TheFD); } void RemoveUnusedFunction::handleOneCallExpr(const CallExpr *E) { const FunctionDecl *FD = E->getDirectCallee(); if (!FD) return; const FunctionDecl *TheFD = getSourceFunctionDecl(FD); addOneReferencedFunction(TheFD); } void RemoveUnusedFunction::handleOneCXXOperatorCallExpr( const CXXOperatorCallExpr *E) { const FunctionDecl *FD = E->getDirectCallee(); if (!FD) return; const CXXMethodDecl *MD = dyn_cast(FD); if (!MD) return; if (const FunctionDecl *OrigFD = MD->getInstantiatedFromMemberFunction()) addOneReferencedFunction(OrigFD); } void RemoveUnusedFunction::addOneFunctionDecl(const FunctionDecl *CanonicalFD) { ValidInstanceNum++; if (ToCounter > 0) { AllValidFunctionDecls.push_back(CanonicalFD); return; } if (ValidInstanceNum == TransformationCounter) { TheFunctionDecl = CanonicalFD; } } void RemoveUnusedFunction::addOneReferencedFunction( const FunctionDecl *FD) { ReferencedFDs.insert(FD->getCanonicalDecl()); } const FunctionTemplateDecl *RemoveUnusedFunction::getTopDescribedTemplate( const FunctionDecl *FD) { FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate(); if (!FTD) return NULL; if (const FunctionTemplateDecl *D = FTD->getInstantiatedFromMemberTemplate()) return D; else return FTD; } bool RemoveUnusedFunction::hasReferencedSpecialization(const FunctionDecl *FD) { if (const FunctionTemplateDecl *FTD = getTopDescribedTemplate(FD)) { for (FunctionTemplateDecl::spec_iterator I = FTD->spec_begin(), E = FTD->spec_end(); I != E; ++I) { if ((*I)->isReferenced()) return true; } } return false; } void RemoveUnusedFunction::setInlinedSystemFunctions(const FunctionDecl *FD) { if (!FD->isInlined()) return; std::string FDNameStr = FD->getNameAsString(); for (InlinedSystemFunctionsMap::iterator I = InlinedSystemFunctions.begin(), E = InlinedSystemFunctions.end(); I != E; ++I) { if (FDNameStr == (*I).second) { ExistingSystemFunctions.insert(FDNameStr); return; } } } bool RemoveUnusedFunction::isInlinedSystemFunction(const FunctionDecl *FD) { std::string FDNameStr = FD->getNameAsString(); InlinedSystemFunctionsMap::iterator I = InlinedSystemFunctions.find(FDNameStr); if (I == InlinedSystemFunctions.end()) return false; return ExistingSystemFunctions.count((*I).second); } void RemoveUnusedFunction::addOneMemberSpecialization( const FunctionDecl *FD, const FunctionDecl *Member) { MemberSpecializationSet *S = MemberToSpecs[Member->getCanonicalDecl()]; if (S == NULL) { S = new MemberSpecializationSet(); MemberToSpecs[Member->getCanonicalDecl()] = S; } S->insert(FD); } void RemoveUnusedFunction::createFuncToExplicitSpecs(const FunctionDecl *FD) { MemberSpecializationSet *S = FuncToExplicitSpecs[FD->getCanonicalDecl()]; if (S == NULL) { S = new MemberSpecializationSet(); FuncToExplicitSpecs[FD->getCanonicalDecl()] = S; } } void RemoveUnusedFunction::addFuncToExplicitSpecs(const FunctionDecl *FD) { TransAssert((FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) && "Invalid template specialization kind!"); const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate(); TransAssert(FTD && "NULL FunctionTemplateDecl!"); const FunctionDecl *TemplatedFD = FTD->getTemplatedDecl(); MemberSpecializationSet *S = FuncToExplicitSpecs[TemplatedFD->getCanonicalDecl()]; if (S != NULL) { S->insert(FD); } } RemoveUnusedFunction::~RemoveUnusedFunction() { for (MemberToSpecializationMap::iterator I = MemberToSpecs.begin(), E = MemberToSpecs.end(); I != E; ++I) { delete ((*I).second); } for (MemberToSpecializationMap::iterator I = MemberToInstantiations.begin(), E = MemberToInstantiations.end(); I != E; ++I) { delete ((*I).second); } delete AnalysisVisitor; delete VisitorWrapper; } cvise-2.3.0/clang_delta/RemoveUnusedFunction.h000066400000000000000000000140551402162750500213710ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNUSED_FUNCTION_H #define REMOVE_UNUSED_FUNCTION_H #include #include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "Transformation.h" #include "clang/Basic/SourceLocation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class UsingDecl; class DeclarationName; class DeclContext; class CXXDependentScopeMemberExpr; class FunctionTemplateDecl; class UnresolvedLookupExpr; class NestedNameSpecifier; class MemberExpr; class CXXOperatorCallExpr; } class RUFAnalysisVisitor; class ExtraReferenceVisitorWrapper; class RemoveUnusedFunction : public Transformation { friend class RUFAnalysisVisitor; friend class ExtraReferenceVisitorWrapper; public: RemoveUnusedFunction(const char *TransName, const char *Desc) : Transformation(TransName, Desc, /*MultipleRewrites*/true), AnalysisVisitor(NULL), VisitorWrapper(NULL), TheFunctionDecl(NULL) { } ~RemoveUnusedFunction(); void handleOneUsingDecl(const clang::FunctionDecl *CurrentFD, const clang::UsingDecl *D); void handleOneCXXDependentScopeMemberExpr( const clang::FunctionDecl *CurrentFD, const clang::CXXDependentScopeMemberExpr *E); void handleOneUnresolvedLookupExpr( const clang::FunctionDecl *CurrentFD, const clang::UnresolvedLookupExpr *E); void handleOneMemberExpr(const clang::MemberExpr *ME); void handleOneCXXOperatorCallExpr(const clang::CXXOperatorCallExpr *E); void handleOneCallExpr(const clang::CallExpr *E); void handleOneFunctionDecl(const clang::FunctionDecl *FD); private: typedef llvm::SmallVector FunctionDeclVector; typedef llvm::DenseMap UsingFunctionDeclsMap; typedef llvm::SmallPtrSet FunctionDeclsSet; typedef llvm::SmallPtrSet MemberSpecializationSet; typedef llvm::DenseMap MemberToSpecializationMap; typedef llvm::SmallPtrSet UsingDeclsSet; typedef std::map InlinedSystemFunctionsMap; typedef std::set SystemFunctionsSet; typedef llvm::SmallSet LocSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void initializeInlinedSystemFunctions(); void doRewriting(); bool hasReferencedSpecialization(const clang::FunctionDecl *FD); clang::SourceLocation getExtensionLocStart(clang::SourceLocation Loc); void removeOneFunctionDecl(const clang::FunctionDecl *FD); void removeMemberSpecializations(const clang::FunctionDecl *FD); void removeRemainingExplicitSpecs(MemberSpecializationSet *ExplicitSpecs); clang::SourceLocation getFunctionOuterLocStart(const clang::FunctionDecl *FD); bool hasValidOuterLocStart(const clang::FunctionTemplateDecl *FTD, const clang::FunctionDecl *FD); void removeOneFunctionDeclGroup(const clang::FunctionDecl *FD); bool isInReferencedSet(const clang::FunctionDecl *FD); bool hasAtLeastOneValidLocation(const clang::FunctionDecl *FD); void addOneFunctionDecl(const clang::FunctionDecl *CanonicalFD); void addOneMemberSpecialization(const clang::FunctionDecl *FD, const clang::FunctionDecl *Member); void createFuncToExplicitSpecs(const clang::FunctionDecl *FD); void addFuncToExplicitSpecs(const clang::FunctionDecl *FD); const clang::FunctionDecl *lookupFunctionDeclShallow( const clang::DeclarationName &DName, const clang::DeclContext *Ctx); const clang::FunctionDecl *getFunctionDeclFromSpecifier( const clang::DeclarationName &Name, const clang::NestedNameSpecifier *NNS); void addOneReferencedFunction(const clang::FunctionDecl *FD); clang::SourceLocation getFunctionLocEnd(clang::SourceLocation LocStart, clang::SourceLocation LocEnd, const clang::FunctionDecl *FD); bool isTokenOperator(clang::SourceLocation Loc); void removeFunctionExplicitInstantiations(const clang::FunctionDecl *FD); void removeOneExplicitInstantiation(const clang::FunctionDecl *Spec); const clang::FunctionTemplateDecl *getTopDescribedTemplate( const clang::FunctionDecl *FD); const clang::FunctionDecl *getSourceFunctionDecl( const clang::FunctionDecl *TheFD); void setInlinedSystemFunctions(const clang::FunctionDecl *FD); bool isInlinedSystemFunction(const clang::FunctionDecl *FD); UsingFunctionDeclsMap UsingFDs; UsingFunctionDeclsMap UsingParentFDs; FunctionDeclsSet ReferencedFDs; FunctionDeclsSet VisitedFDs; FunctionDeclsSet RemovedFDs; UsingDeclsSet VisitedUsingDecls; MemberToSpecializationMap MemberToSpecs; MemberToSpecializationMap FuncToExplicitSpecs; MemberToSpecializationMap MemberToInstantiations; InlinedSystemFunctionsMap InlinedSystemFunctions; SystemFunctionsSet ExistingSystemFunctions; LocSet VisitedLocations; FunctionDeclVector AllValidFunctionDecls; RUFAnalysisVisitor *AnalysisVisitor; ExtraReferenceVisitorWrapper *VisitorWrapper; const clang::FunctionDecl *TheFunctionDecl; // Unimplemented RemoveUnusedFunction(); RemoveUnusedFunction(const RemoveUnusedFunction &); void operator=(const RemoveUnusedFunction &); }; #endif cvise-2.3.0/clang_delta/RemoveUnusedOuterClass.cpp000066400000000000000000000105441402162750500222220ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveUnusedOuterClass.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/Lexer.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass an unused outer class if \n\ * the outer class doesn't have any base class, and \n\ * the outer class does not have any described template, and \n\ * the outer class is not been referenced \n\ "; static RegisterTransformation Trans("remove-unused-outer-class", DescriptionMsg); class RemoveUnusedOuterClassVisitor : public RecursiveASTVisitor { public: explicit RemoveUnusedOuterClassVisitor( RemoveUnusedOuterClass *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); bool VisitRecordTypeLoc(RecordTypeLoc TLoc); private: RemoveUnusedOuterClass *ConsumerInstance; }; bool RemoveUnusedOuterClassVisitor::VisitRecordTypeLoc(RecordTypeLoc TLoc) { const CXXRecordDecl *RD = dyn_cast(TLoc.getDecl()); ConsumerInstance->UsedCXXRDSet.insert(RD->getCanonicalDecl()); return true; } bool RemoveUnusedOuterClassVisitor::VisitCXXRecordDecl( CXXRecordDecl *CXXRD) { if (ConsumerInstance->isInIncludedFile(CXXRD) || ConsumerInstance->isSpecialRecordDecl(CXXRD) || !CXXRD->hasDefinition() || dyn_cast(CXXRD) || CXXRD->hasUserDeclaredConstructor() || CXXRD->hasUserDeclaredDestructor() || CXXRD->getDescribedClassTemplate() || CXXRD->getNumBases()) return true; ConsumerInstance->CXXRDDefSet.insert(CXXRD->getDefinition()); return true; } void RemoveUnusedOuterClass::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveUnusedOuterClassVisitor(this); } void RemoveUnusedOuterClass::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); analyzeCXXRDSet(); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); removeOuterClass(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveUnusedOuterClass::analyzeCXXRDSet() { for (CXXRecordDeclSetVector::iterator I = CXXRDDefSet.begin(), E = CXXRDDefSet.end(); I != E; ++I) { const CXXRecordDecl *Def = (*I); if (UsedCXXRDSet.count(Def->getCanonicalDecl())) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) TheCXXRDDef = Def; } } void RemoveUnusedOuterClass::removeOuterClass() { TransAssert(TheCXXRDDef && "NULL Base CXXRD!"); SourceLocation LocStart = TheCXXRDDef->getBeginLoc(); SourceLocation LocEnd = RewriteHelper->getEndLocationUntil(LocStart, '{'); TransAssert(LocEnd.isValid() && "Invalid Location!"); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); const DeclContext *Ctx = dyn_cast(TheCXXRDDef); for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if ((*I)->isImplicit()) continue; const AccessSpecDecl *AS = dyn_cast(*I); if (!AS) continue; TheRewriter.RemoveText(AS->getSourceRange()); } LocStart = TheCXXRDDef->getBraceRange().getEnd(); LocEnd = RewriteHelper->getLocationUntil(LocStart, ';'); if (LocStart.isInvalid() || LocEnd.isInvalid()) return; TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); } RemoveUnusedOuterClass::~RemoveUnusedOuterClass(void) { delete CollectionVisitor; } cvise-2.3.0/clang_delta/RemoveUnusedOuterClass.h000066400000000000000000000031751402162750500216710ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNUSED_OUTER_CLASS_H #define REMOVE_UNUSED_OUTER_CLASS_H #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXRecordDecl; } class RemoveUnusedOuterClassVisitor; class RemoveUnusedOuterClass : public Transformation { friend class RemoveUnusedOuterClassVisitor; public: RemoveUnusedOuterClass(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheCXXRDDef(NULL) { } ~RemoveUnusedOuterClass(void); private: typedef llvm::SmallPtrSet CXXRecordDeclSet; typedef llvm::SetVector CXXRecordDeclSetVector; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void analyzeCXXRDSet(); void removeOuterClass(); CXXRecordDeclSet UsedCXXRDSet; CXXRecordDeclSetVector CXXRDDefSet; RemoveUnusedOuterClassVisitor *CollectionVisitor; const clang::CXXRecordDecl *TheCXXRDDef; // Unimplemented RemoveUnusedOuterClass(void); RemoveUnusedOuterClass(const RemoveUnusedOuterClass &); void operator=(const RemoveUnusedOuterClass &); }; #endif cvise-2.3.0/clang_delta/RemoveUnusedStructField.cpp000066400000000000000000000274201402162750500223670ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveUnusedStructField.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove unreferenced struct fields. This pass also removes the corresponding \ intialization expression for a variable declared as the struct under \ transformation. Currenttly this pass doesn't handle nested struct \ definition well. \n"; static RegisterTransformation Trans("remove-unused-field", DescriptionMsg); class RemoveUnusedStructFieldVisitor : public RecursiveASTVisitor { public: explicit RemoveUnusedStructFieldVisitor(RemoveUnusedStructField *Instance) : ConsumerInstance(Instance) { } bool VisitFieldDecl(FieldDecl *FD); bool VisitDesignatedInitExpr(DesignatedInitExpr *DIE); private: RemoveUnusedStructField *ConsumerInstance; }; class RemoveUnusedStructFieldRewriteVisitor : public RecursiveASTVisitor { public: explicit RemoveUnusedStructFieldRewriteVisitor( RemoveUnusedStructField *Instance) : ConsumerInstance(Instance) { } bool VisitRecordDecl(RecordDecl *RD); bool VisitVarDecl(VarDecl *VD); private: RemoveUnusedStructField *ConsumerInstance; }; bool RemoveUnusedStructFieldVisitor::VisitFieldDecl(FieldDecl *FD) { if(ConsumerInstance->isInIncludedFile(FD)) return true; const RecordDecl *RD = FD->getParent(); if (FD->isReferenced() || !RD->isStruct() || ConsumerInstance->isSpecialRecordDecl(RD)) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->setBaseLine(RD, FD); } return true; } bool RemoveUnusedStructFieldVisitor::VisitDesignatedInitExpr(DesignatedInitExpr *DIE) { return true; } bool RemoveUnusedStructFieldRewriteVisitor::VisitRecordDecl(RecordDecl *RD) { if (ConsumerInstance->isSpecialRecordDecl(RD)) return true; const RecordDecl *RDDef = RD->getDefinition(); if (!RDDef) return true; if (ConsumerInstance->RecordDeclToField[RD]) return true; unsigned Idx = 0; for (RecordDecl::field_iterator I = RDDef->field_begin(), E = RDDef->field_end(); I != E; ++I) { const FieldDecl *FD = (*I); const Type *FDTy = FD->getType().getTypePtr(); const RecordDecl *BaseRD = ConsumerInstance->getBaseRecordDef(FDTy); if (BaseRD) ConsumerInstance->handleOneRecordDecl(RDDef, BaseRD, FD, Idx); Idx++; } return true; } bool RemoveUnusedStructFieldRewriteVisitor::VisitVarDecl(VarDecl *VD) { if (!VD->hasInit()) return true; ConsumerInstance->handleOneVarDecl(VD); return true; } void RemoveUnusedStructField::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RemoveUnusedStructFieldVisitor(this); RewriteVisitor = new RemoveUnusedStructFieldRewriteVisitor(this); } void RemoveUnusedStructField::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheRecordDecl && "NULL TheRecordDecl!"); TransAssert(TheFieldDecl && "NULL TheFunctionDecl!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); removeFieldDecl(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveUnusedStructField::setBaseLine(const RecordDecl *RD, const FieldDecl *FD) { TheRecordDecl = RD; TheFieldDecl = FD; IndexVector *IdxVec = new IndexVector(); unsigned int Idx = FD->getFieldIndex(); IdxVec->push_back(Idx); RecordDeclToField[RD] = IdxVec; FieldToIdxVector[FD] = IdxVec; // IsLastField = (FD->getNextDeclInContext() == NULL); RecordDecl::field_iterator I = RD->field_begin(); IsFirstField = (FD == (*I)); RecordDecl::field_iterator E = RD->field_end(); for (; I != E; ++I) { NumFields++; } } void RemoveUnusedStructField::handleOneRecordDecl(const RecordDecl *RD, const RecordDecl *BaseRD, const FieldDecl *FD, unsigned int Idx) { IndexVector *BaseIdxVec = RecordDeclToField[BaseRD]; if (!BaseIdxVec) return; IndexVector *NewIdxVec = RecordDeclToField[RD]; if (!NewIdxVec) { NewIdxVec = new IndexVector(); RecordDeclToField[RD] = NewIdxVec; } NewIdxVec->push_back(Idx); FieldToIdxVector[FD] = BaseIdxVec; } void RemoveUnusedStructField::handleOneVarDecl(const VarDecl *VD) { const Type *Ty = VD->getType().getTypePtr(); const RecordDecl *RD = getBaseRecordDef(Ty); if (!RD) return; IndexVector *IdxVec = RecordDeclToField[RD]; if (!IdxVec) return; const Expr *InitE = VD->getInit(); TransAssert(InitE && "Need initializer!"); ExprVector InitExprs; getInitExprs(Ty, InitE, IdxVec, InitExprs); for (ExprVector::iterator I = InitExprs.begin(), E = InitExprs.end(); I != E; ++I) { if (dyn_cast(*I)) continue; removeOneInitExpr(*I); } } const FieldDecl *RemoveUnusedStructField::getFieldDeclByIdx( const RecordDecl *RD, unsigned int Idx) { unsigned I = 0; for (RecordDecl::field_iterator RI = RD->field_begin(), RE = RD->field_end(); RI != RE; ++RI, ++I) { if (I == Idx) return (*RI); } return NULL; } const Expr *RemoveUnusedStructField::getInitExprFromDesignatedInitExpr( const InitListExpr *ILE, int InitListIdx, const FieldDecl *FD) { int NumInits = ILE->getNumInits(); llvm::DenseMap LeftInits; int LastFDIdx = -1; for (int I = 0; I < NumInits; ++I) { const Expr *Init = ILE->getInit(I); if (const DesignatedInitExpr *DIE = dyn_cast(Init)) { if (DIE->getNumSubExprs() < 1) { LeftInits[I] = Init; LastFDIdx = I; } else { const DesignatedInitExpr::Designator *DS = DIE->getDesignator(0); const FieldDecl *CurrFD = DS->getField(); if ((CurrFD && FD == CurrFD) || (CurrFD == NULL && DS->getFieldName() == FD->getIdentifier())) { IsFirstField = (I == 0); return Init; } if (CurrFD) { LastFDIdx = CurrFD->getFieldIndex(); } else { LastFDIdx = I; } } } else { LastFDIdx++; LeftInits[LastFDIdx] = Init; } } const Expr *Init = LeftInits[++LastFDIdx]; if (Init) { IsFirstField = (LastFDIdx == 0); return Init; } IsFirstField = (InitListIdx == 0); return ILE->getInit(InitListIdx); } void RemoveUnusedStructField::getInitExprs(const Type *Ty, const Expr *E, const IndexVector *IdxVec, ExprVector &InitExprs) { const ArrayType *ArrayTy = dyn_cast(Ty); if (ArrayTy) { if (const InitListExpr *ILE = dyn_cast(E)) { TransAssert(ILE && "Invalid array initializer!"); unsigned int NumInits = ILE->getNumInits(); Ty = ArrayTy->getElementType().getTypePtr(); for (unsigned I = 0; I < NumInits; ++I) { const Expr *Init = ILE->getInit(I); getInitExprs(Ty, Init, IdxVec, InitExprs); } } return; } const InitListExpr *ILE = dyn_cast(E); if (!ILE) return; // ILE can be a list of DesignatedInitExpr(s). // Extract it's syntactic form in such case. bool HasDesignatedInit = false; if (ILE->isSemanticForm()) { ILE = ILE->getSyntacticForm() == nullptr ? ILE : ILE->getSyntacticForm(); for (unsigned I = 0; I < ILE->getNumInits(); I++) { if (isa(ILE->getInit(I))) { HasDesignatedInit = true; break; } } } const RecordType *RT = NULL; if (Ty->isUnionType()) { RT = Ty->getAsUnionType(); } else if (Ty->isStructureType()) { RT = Ty->getAsStructureType(); } else { TransAssert(0 && "Bad RecordType!"); } const RecordDecl *RD = RT->getDecl(); unsigned int VecSz = IdxVec->size(); for (IndexVector::const_iterator FI = IdxVec->begin(), FE = IdxVec->end(); FI != FE; ++FI) { const FieldDecl *FD = getFieldDeclByIdx(RD, (*FI)); TransAssert(FD && "NULL FieldDecl!"); IndexVector *FieldIdxVec = FieldToIdxVector[FD]; TransAssert(FieldIdxVec && "Cannot find FieldIdxVec!"); Ty = FD->getType().getTypePtr(); const Expr *Init; unsigned int InitListIdx; if (RD->isUnion()) InitListIdx = 0; else InitListIdx = (*FI); if (InitListIdx >= ILE->getNumInits()) return; Init = ILE->getInit(InitListIdx); if (FD == TheFieldDecl) { if (HasDesignatedInit) { Init = getInitExprFromDesignatedInitExpr(ILE, InitListIdx, FD); } InitExprs.push_back(Init); TransAssert((VecSz == 1) && "Bad IndexVector size!"); (void)VecSz; } else { getInitExprs(Ty, Init, FieldIdxVec, InitExprs); } } } void RemoveUnusedStructField::removeOneInitExpr(const Expr *E) { TransAssert(NumFields && "NumFields cannot be zero!"); SourceRange ExpRange = E->getSourceRange(); SourceLocation StartLoc = ExpRange.getBegin(); SourceLocation EndLoc = ExpRange.getEnd(); if (NumFields == 1) { // The last field can optionally have a trailing comma // If this is the only field also the comma has to be removed SourceLocation NewEndLoc = RewriteHelper->getEndLocationUntil(ExpRange, '}'); NewEndLoc = NewEndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, NewEndLoc)); return; } else if (IsFirstField) { EndLoc = RewriteHelper->getEndLocationUntil(ExpRange, ','); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); return; } const char *Buf = SrcManager->getCharacterData(StartLoc); int Offset = 0; while (*Buf != ',') { Buf--; Offset--; } StartLoc = StartLoc.getLocWithOffset(Offset); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); } const RecordDecl *RemoveUnusedStructField::getBaseRecordDef(const Type *Ty) { const ArrayType *ArrayTy = dyn_cast(Ty); if (ArrayTy) { Ty = getArrayBaseElemType(ArrayTy); } if (!Ty->isStructureType()) return NULL; const RecordType *RT = Ty->getAsStructureType(); return RT->getDecl()->getDefinition(); } void RemoveUnusedStructField::removeFieldDecl(void) { // FIXME: we don't handle nested struct definition well. // For example, // struct S1 { // struct S2 { // int f1; // } f1; // struct S2 f2; // } // will be transformed to // struct S1 { // struct S2 f2; // } // Thus we will leave an incomplete struct S2 RewriteHelper->removeFieldDecl(TheFieldDecl); } RemoveUnusedStructField::~RemoveUnusedStructField(void) { delete CollectionVisitor; delete RewriteVisitor; for (RecordDeclToFieldIdxVectorMap::iterator I = RecordDeclToField.begin(), E = RecordDeclToField.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/RemoveUnusedStructField.h000066400000000000000000000056231402162750500220350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNUSED_STRUCT_FIELD_H #define REMOVE_UNUSED_STRUCT_FIELD_H #include "Transformation.h" #include "llvm/ADT/DenseMap.h" namespace clang { class DeclGroupRef; class ASTContext; class FieldDecl; class RecordDecl; class Type; class VarDecl; } class RemoveUnusedStructFieldVisitor; class RemoveUnusedStructFieldRewriteVisitor; class RemoveUnusedStructField : public Transformation { friend class RemoveUnusedStructFieldVisitor; friend class RemoveUnusedStructFieldRewriteVisitor; public: RemoveUnusedStructField(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheRecordDecl(NULL), TheFieldDecl(NULL), NumFields(0), IsFirstField(false) { } ~RemoveUnusedStructField(void); private: typedef llvm::DenseMap RecordDeclToFieldIdxVectorMap; typedef llvm::DenseMap FieldDeclToIdxVectorMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); const clang::RecordDecl *getBaseRecordDef(const clang::Type *Ty); void handleOneRecordDecl(const clang::RecordDecl *RD, const clang::RecordDecl *BaseRD, const clang::FieldDecl *FD, unsigned int Idx); void handleOneVarDecl(const clang::VarDecl *VD); void setBaseLine(const clang::RecordDecl *RD, const clang::FieldDecl *FD); const clang::Expr *getInitExprFromDesignatedInitExpr( const clang::InitListExpr *ILE, int InitListIdx, const clang::FieldDecl *FD); void getInitExprs(const clang::Type *Ty, const clang::Expr *E, const IndexVector *IdxVec, ExprVector &InitExprs); const clang::FieldDecl *getFieldDeclByIdx(const clang::RecordDecl *RD, unsigned int Idx); void removeOneInitExpr(const clang::Expr *E); void removeFieldDecl(void); RecordDeclToFieldIdxVectorMap RecordDeclToField; FieldDeclToIdxVectorMap FieldToIdxVector; RemoveUnusedStructFieldVisitor *CollectionVisitor; RemoveUnusedStructFieldRewriteVisitor *RewriteVisitor; const clang::RecordDecl *TheRecordDecl; const clang::FieldDecl *TheFieldDecl; unsigned int NumFields; bool IsFirstField; // Unimplemented RemoveUnusedStructField(void); RemoveUnusedStructField(const RemoveUnusedStructField &); void operator=(const RemoveUnusedStructField &); }; #endif cvise-2.3.0/clang_delta/RemoveUnusedVar.cpp000066400000000000000000000127221402162750500206660ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RemoveUnusedVar.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Remove unused local/global variable declarations. \n"; static RegisterTransformation Trans("remove-unused-var", DescriptionMsg); class RemoveUnusedVarAnalysisVisitor : public RecursiveASTVisitor { public: explicit RemoveUnusedVarAnalysisVisitor(RemoveUnusedVar *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitDeclStmt(DeclStmt *DS); bool VisitCXXCatchStmt(CXXCatchStmt *DS); private: RemoveUnusedVar *ConsumerInstance; }; bool RemoveUnusedVarAnalysisVisitor::VisitVarDecl(VarDecl *VD) { if (ConsumerInstance->isInIncludedFile(VD)) return true; if (VD->isReferenced() || dyn_cast(VD) || VD->isStaticDataMember()) return true; SourceRange VarRange = VD->getSourceRange(); if (VarRange.getEnd().isInvalid()) return true; if (ConsumerInstance->SkippedVars.count(VD->getCanonicalDecl())) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ToCounter > 0) { ConsumerInstance->AllValidVarDecls.push_back(VD); return true; } if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheVarDecl = VD; } return true; } bool RemoveUnusedVarAnalysisVisitor::VisitDeclStmt(DeclStmt *DS) { for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { VarDecl *CurrDecl = dyn_cast(*I); if (CurrDecl) { DeclGroupRef DGR = DS->getDeclGroup(); ConsumerInstance->VarToDeclGroup[CurrDecl] = DGR; } } return true; } bool RemoveUnusedVarAnalysisVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) { const VarDecl *VD = S->getExceptionDecl(); if (VD) { ConsumerInstance->SkippedVars.insert(VD->getCanonicalDecl()); } return true; } void RemoveUnusedVar::Initialize(ASTContext &context) { Transformation::Initialize(context); AnalysisVisitor = new RemoveUnusedVarAnalysisVisitor(this); } bool RemoveUnusedVar::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { VarDecl *VD = dyn_cast(*I); if (VD) VarToDeclGroup[VD] = D; } return true; } void RemoveUnusedVar::HandleTranslationUnit(ASTContext &Ctx) { AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } if (ToCounter > ValidInstanceNum) { TransError = TransToCounterTooBigError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RemoveUnusedVar::doRewriting() { if (ToCounter <= 0) { TransAssert(TheVarDecl && "NULL TheVarDecl!"); removeVarDecl(TheVarDecl); return; } TransAssert((TransformationCounter <= static_cast(AllValidVarDecls.size())) && "TransformationCounter is larger than the number of decls!"); TransAssert((ToCounter <= static_cast(AllValidVarDecls.size())) && "ToCounter is larger than the number of decls!"); for (int I = ToCounter; I >= TransformationCounter; --I) { TransAssert((I >= 1) && "Invalid Index!"); const VarDecl *VD = AllValidVarDecls[I-1]; TransAssert(VD && "NULL FunctionDecl!"); removeVarDecl(VD); } } void RemoveUnusedVar::removeVarDeclFromLinkageSpecDecl( const LinkageSpecDecl *LinkageD, const VarDecl *VD) { const DeclContext *Ctx = LinkageSpecDecl::castToDeclContext(LinkageD); unsigned NumDecls = 0; for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { NumDecls++; if (NumDecls > 1) break; } if (NumDecls <= 1) { RewriteHelper->removeDecl(LinkageD); return; } else { RewriteHelper->removeVarDecl(VD); } } void RemoveUnusedVar::removeVarDecl(const VarDecl *VD) { const DeclContext *Ctx = VD->getDeclContext(); if (const LinkageSpecDecl *LinkageDecl = dyn_cast(Ctx)) { removeVarDeclFromLinkageSpecDecl(LinkageDecl, VD); return; } else if (dyn_cast(Ctx)) { // if a var is declared inside a namespace, we don't know // which declaration group it belongs to. RewriteHelper->removeVarDecl(VD); return; } llvm::DenseMap::iterator DI = VarToDeclGroup.find(VD); if (DI == VarToDeclGroup.end()) { // We don't know the decl group that the var decl belongs to. RewriteHelper->removeVarDecl(VD); } else { RewriteHelper->removeVarDecl(VD, (*DI).second); } } RemoveUnusedVar::~RemoveUnusedVar(void) { delete AnalysisVisitor; } cvise-2.3.0/clang_delta/RemoveUnusedVar.h000066400000000000000000000034611402162750500203330ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REMOVE_UNUSED_VAR_H #define REMOVE_UNUSED_VAR_H #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; class LinkageSpecDecl; } class RemoveUnusedVarAnalysisVisitor; class RemoveUnusedVar : public Transformation { friend class RemoveUnusedVarAnalysisVisitor; public: RemoveUnusedVar(const char *TransName, const char *Desc) : Transformation(TransName, Desc, /*MultipleRewrites*/true), AnalysisVisitor(NULL), TheVarDecl(NULL) { } ~RemoveUnusedVar(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doRewriting(); void removeVarDecl(const clang::VarDecl *VD); void removeVarDeclFromLinkageSpecDecl(const clang::LinkageSpecDecl *LinkageD, const clang::VarDecl *VD); llvm::DenseMap VarToDeclGroup; llvm::SmallPtrSet SkippedVars; llvm::SmallVector AllValidVarDecls; RemoveUnusedVarAnalysisVisitor *AnalysisVisitor; clang::VarDecl *TheVarDecl; // Unimplemented RemoveUnusedVar(void); RemoveUnusedVar(const RemoveUnusedVar &); void operator=(const RemoveUnusedVar &); }; #endif cvise-2.3.0/clang_delta/RenameCXXMethod.cpp000066400000000000000000000676041402162750500205400ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RenameCXXMethod.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Another pass to increase readability of reduced code. \ It renames CXX methods names to m_fn1, m_fn2, ...\n"; static RegisterTransformation Trans("rename-cxx-method", DescriptionMsg); class RenameCXXMethodCollectionVisitor : public RecursiveASTVisitor { public: explicit RenameCXXMethodCollectionVisitor(RenameCXXMethod *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *FD); bool VisitCXXMethodDecl(CXXMethodDecl *MD); private: RenameCXXMethod *ConsumerInstance; }; // ISSUE: // we can't handle the case below: // struct A { // int abc; // static int test(int); // enum { // value = (1 == sizeof(test(abc))) // }; // }; // The reason is that somehow expr (1== sizeof(test(abc))) // is not presented in Clang's AST representation. class RenameCXXMethodVisitor : public RecursiveASTVisitor { public: explicit RenameCXXMethodVisitor(RenameCXXMethod *Instance) : ConsumerInstance(Instance) { } bool TraverseClassTemplateDecl(ClassTemplateDecl *D); bool VisitCXXMethodDecl(CXXMethodDecl *MD); bool VisitFunctionDecl(FunctionDecl *FD); bool VisitCXXRecordDecl(CXXRecordDecl *FD); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitMemberExpr(MemberExpr *ME); bool VisitCallExpr(CallExpr *CE); // we have to enable visiting template instantiations, otherwise, // we won't be able to see some explicit instantiation code, e.g.: // template class A { // T* foo(T* __p) <--- foo would be missing // { __p; } // }; // extern template class basic_string; bool shouldVisitTemplateInstantiations() { return true; } private: void TraverseClassInstantiations(ClassTemplateDecl *D); RenameCXXMethod *ConsumerInstance; }; bool RenameCXXMethodCollectionVisitor::VisitCXXRecordDecl(CXXRecordDecl *RD) { if (ConsumerInstance->isInIncludedFile(RD) || !RD->hasDefinition()) return true; const CXXRecordDecl *RDDef = RD->getDefinition(); ConsumerInstance->handleOneCXXRecordDecl(RDDef); return true; } bool RenameCXXMethodCollectionVisitor::VisitCXXMethodDecl(CXXMethodDecl *MD) { if (ConsumerInstance->isInIncludedFile(MD)) return true; const CXXMethodDecl *CanonicalMD = MD->getCanonicalDecl(); if(ConsumerInstance->NewMethodNames.find(CanonicalMD) != ConsumerInstance->NewMethodNames.end()) return true; ConsumerInstance->handleOneMemberTemplateFunction(CanonicalMD); return true; } bool RenameCXXMethodVisitor::VisitCXXRecordDecl(CXXRecordDecl *RD) { ConsumerInstance->setClassInstantiationFlag(RD); ConsumerInstance->clearFunctionInstantiationFlag(); return true; } bool RenameCXXMethodVisitor::VisitFunctionDecl(FunctionDecl *FD) { ConsumerInstance->CurrentFD = FD; const CXXMethodDecl *MD = dyn_cast(FD); if (!MD) { ConsumerInstance->setFunctionInstantiationFlag(FD); ConsumerInstance->clearClassInstantiationFlag(); } return true; } void RenameCXXMethodVisitor::TraverseClassInstantiations( ClassTemplateDecl *D) { for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { ClassTemplateSpecializationDecl* SpecD = (*I); switch (SpecD->getSpecializationKind()) { case TSK_Undeclared: case TSK_ImplicitInstantiation: // Keep track if we are inside class instantiations. // We use a queue because we could have nested CXXRecord definition // and implicit instantiations ConsumerInstance->InstantiationQueue.push_back(SpecD); TraverseDecl(SpecD); ConsumerInstance->InstantiationQueue.pop_back(); break; default: // TSK_ExplicitInstantiationDeclaration: // TSK_ExplicitInstantiationDefinition: // TSK_ExplicitSpecialization: break; } } } bool RenameCXXMethodVisitor::TraverseClassTemplateDecl(ClassTemplateDecl *D) { CXXRecordDecl* TmplDecl = D->getTemplatedDecl(); if (TmplDecl) TraverseDecl(TmplDecl); if (TemplateParameterList *TmplList = D->getTemplateParameters()) { for (TemplateParameterList::iterator I = TmplList->begin(), E = TmplList->end(); I != E; ++I) { TraverseDecl(*I); } } if (D != D->getCanonicalDecl()) return true; TraverseClassInstantiations(D); return true; } bool RenameCXXMethodVisitor::VisitCXXMethodDecl(CXXMethodDecl *MD) { if (ConsumerInstance->isSpecialCXXMethod(MD) || ConsumerInstance->isInIncludedFile(MD)) return true; const CXXMethodDecl *CanonicalMD = MD->getCanonicalDecl(); llvm::DenseMap::iterator I = ConsumerInstance->NewMethodNames.find(CanonicalMD); if (I != ConsumerInstance->NewMethodNames.end()) { ConsumerInstance->RewriteHelper->replaceFunctionDeclName(MD, (*I).second); return true; } TemplateSpecializationKind K = MD->getTemplateSpecializationKind(); if (const FunctionDecl *MemberFD = MD->getInstantiatedFromMemberFunction()) { if (K != TSK_ExplicitSpecialization) return true; const CXXMethodDecl *MemberMD = dyn_cast(MemberFD); TransAssert(MemberMD && "Invalid Member FD!"); if (ConsumerInstance->VisitedSpecializedMethods.count( MD->getCanonicalDecl())) return true; ConsumerInstance->VisitedSpecializedMethods.insert( MD->getCanonicalDecl()); CanonicalMD = MemberMD->getCanonicalDecl(); I = ConsumerInstance->NewMethodNames.find(CanonicalMD); TransAssert((I != ConsumerInstance->NewMethodNames.end()) && "Cannot find member function!"); ConsumerInstance->RewriteHelper->replaceFunctionDeclName(MD, (*I).second); return true; } // only need to rewrite explicit instantiations if ((K == TSK_ExplicitInstantiationDeclaration) || (K == TSK_ExplicitInstantiationDefinition)) { ConsumerInstance->rewriteFunctionTemplateExplicitInstantiation(MD); } return true; } bool RenameCXXMethodVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { const ValueDecl *VD = DRE->getDecl(); const CXXMethodDecl *MD = dyn_cast(VD); if (!MD) return true; if (!ConsumerInstance->isExplicit(MD)) return true; std::string NewName = ""; if (!ConsumerInstance->getMethodNewName(MD, NewName)) return true; TransAssert((NewName != "") && "Bad new name!"); if (DRE->hasQualifier()) { NestedNameSpecifierLoc QualLoc = DRE->getQualifierLoc(); ConsumerInstance->RewriteHelper->replaceCXXMethodNameAfterQualifier( &QualLoc, MD, NewName); } else { ConsumerInstance->TheRewriter.ReplaceText(DRE->getBeginLoc(), MD->getNameAsString().size(), NewName); } return true; } bool RenameCXXMethodVisitor::VisitMemberExpr(MemberExpr *ME) { const ValueDecl *VD = ME->getMemberDecl(); const CXXMethodDecl *MD = dyn_cast(VD); if (!MD) return true; if (!ConsumerInstance->isExplicit(MD)) { return true; } std::string NewName = ""; if (!ConsumerInstance->getMethodNewName(MD, NewName)) return true; TransAssert((NewName != "") && "Bad new name!"); if (ME->hasQualifier()) { NestedNameSpecifierLoc QualLoc = ME->getQualifierLoc(); ConsumerInstance->RewriteHelper->replaceCXXMethodNameAfterQualifier( &QualLoc, MD, NewName); } else { ConsumerInstance->TheRewriter.ReplaceText(ME->getMemberLoc(), MD->getNameAsString().size(), NewName); } return true; } bool RenameCXXMethodVisitor::VisitCallExpr(CallExpr *CE) { // handled by VisitMemberExpr if (CE->getDirectCallee()) return true; // deal with UnresolvedLookupExpr const Expr *E = CE->getCallee(); ConsumerInstance->rewriteDependentExpr(E); return true; } void RenameCXXMethod::Initialize(ASTContext &context) { Transformation::Initialize(context); MethodCollectionVisitor = new RenameCXXMethodCollectionVisitor(this); RenameVisitor = new RenameCXXMethodVisitor(this); ValidInstanceNum = 1; } bool RenameCXXMethod::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { MethodCollectionVisitor->TraverseDecl(*I); } return true; } void RenameCXXMethod::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) { if (hasValidMethods()) ValidInstanceNum = 1; else ValidInstanceNum = 0; return; } if (!hasValidMethods()) { TransError = TransNoValidFunsError; return; } else if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RenameVisitor && "NULL RenameVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RenameVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool RenameCXXMethod::hasValidMethods() { return ((NewMethodNames.size() != 0) && DoRenaming); } // note that we don't handle the possible ambiguity here, e.g. // class A { // public: // virtual void foo(); // }; // class B { // public: // virtual void foo(); // }; // class C : public A, B { // virtual void foo(); // }; // In this example, getNumInheritedFunctions(C) will return // 2, but it doesn't really matter --- the number 2 is only used // for numbering non-virtual functions. // We are fine unless we don't rename a non-virtual function to // a possible virtual function, either defined in the same // class or inherited from a base. // Furthermore, we don't want to hide any function in // the base class through renaming, for example: // class A { // void foo(); // }; // class B : public A { // void bar(); // }; // // the transformation below is bad: // class A { // void m_fn1(); // }; // class B : public A { // void m_fn1(); // }; unsigned int RenameCXXMethod::getNumInheritedFunctions( const CXXRecordDecl *RD) { TransAssert(RD->isThisDeclarationADefinition() && "Not a definition!"); unsigned int Num = 0; for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); if (!Base) continue; const CXXRecordDecl *CanonicalBase = Base->getCanonicalDecl(); // e.g., // template struct A; // template struct B : A { // void foo() {} // }; if (!Base->hasDefinition() && Base->getDescribedClassTemplate()) continue; CXXRecordDeclToNumMap::iterator NI = NumMemberFunctions.find(CanonicalBase); if (NI != NumMemberFunctions.end()) { Num += NI->second; continue; } if (!Base->hasDefinition()) continue; const CXXRecordDecl *BaseDef = Base->getDefinition(); handleOneCXXRecordDecl(BaseDef); Num += NumMemberFunctions[CanonicalBase]; } return Num; } bool RenameCXXMethod::isValidName(const StringRef &Name) { size_t PrefixLen = MethodNamePrefix.length(); StringRef NamePrefix = Name.substr(0, PrefixLen); if (!NamePrefix.equals(MethodNamePrefix)) return false; llvm::APInt Num; return !Name.drop_front(PrefixLen).getAsInteger(10, Num); } void RenameCXXMethod::addOneMethodName(const CXXMethodDecl *MD, unsigned int /*Num*/) { const CXXMethodDecl *CanonicalMD = MD->getCanonicalDecl(); TransAssert((NewMethodNames.find(CanonicalMD) == NewMethodNames.end()) && "Duplicate CXXMethodDecl!"); std::stringstream SS; // SS << MethodNamePrefix << Num; NumRenamedMethods++; SS << MethodNamePrefix << NumRenamedMethods; NewMethodNames[CanonicalMD] = SS.str(); // Now we check if the old name actually has a valid format, i.e. m_fn([0-9]+) // if not, set DoRenaming to be false, then we will need to // do renaming later. if (!isValidName(CanonicalMD->getNameAsString())) DoRenaming = true; } void RenameCXXMethod::addOneInheritedName(const CXXMethodDecl *MD, const CXXMethodDecl *BaseMD) { const CXXMethodDecl *CanonicalMD = MD->getCanonicalDecl(); CXXMethodDeclToNameMap::iterator I = NewMethodNames.find(CanonicalMD); (void)I; TransAssert((I == NewMethodNames.end()) && "Duplicate CXXMethodDecl!"); const CXXMethodDecl *CanonicalBaseMD = BaseMD->getCanonicalDecl(); // MD may be inherited of a member function of a class template if (const FunctionDecl *FD = CanonicalBaseMD->getInstantiatedFromMemberFunction()) { CanonicalBaseMD = dyn_cast(FD); TransAssert(CanonicalBaseMD && "bad conversion from FD to MD!"); } CXXMethodDeclToNameMap::iterator BaseI = NewMethodNames.find(CanonicalBaseMD); TransAssert((BaseI != NewMethodNames.end()) && "Cannot find base CXXMethodDecl!"); NewMethodNames[CanonicalMD] = BaseI->second; } void RenameCXXMethod::handleOneCXXRecordDecl(const CXXRecordDecl *RD) { TransAssert(RD->isThisDeclarationADefinition() && "Can only handle class definition!"); if (VisitedCXXRecordDecls.count(RD)) return; VisitedCXXRecordDecls.insert(RD); // We need to skip explicit instantiations // Note that shouldVisitTemplateInstantiations is false here, // so we don't need to worry about implicit instantiations if (const ClassTemplateSpecializationDecl *Spec = dyn_cast(RD)) { TemplateSpecializationKind K = Spec->getSpecializationKind(); if ((K == TSK_ExplicitInstantiationDefinition) || (K == TSK_ExplicitInstantiationDeclaration)) return; } unsigned int NumFuns = getNumInheritedFunctions(RD); CXXMethodDeclSet NonVirtualFuns; for (CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { const CXXMethodDecl *MD = (*I); if (isSpecialCXXMethod(MD)) continue; if (!MD->isVirtual()) { NonVirtualFuns.insert(MD); continue; } CXXMethodDecl::method_iterator MI = MD->begin_overridden_methods(); if (MI == MD->end_overridden_methods()) { // new virtual function NumFuns++; addOneMethodName(MD, NumFuns); } else { // if MD is overidden from any base class, // it has been counted, so we don't need to increase NumFuns. addOneInheritedName(MD, *MI); } } const CXXRecordDecl *CanonicalRD = RD->getCanonicalDecl(); for (CXXMethodDeclSet::iterator MI = NonVirtualFuns.begin(), ME = NonVirtualFuns.end(); MI != ME; ++MI) { NumFuns++; const CXXMethodDecl *MD = (*MI); addOneMethodName(MD, NumFuns); } NumMemberFunctions[CanonicalRD] = NumFuns; } bool RenameCXXMethod::isSpecialCXXMethod(const CXXMethodDecl *MD) { if (dyn_cast(MD) || dyn_cast(MD) || dyn_cast(MD)) return true; SmallVector PreventedBy; if (MD->isUsualDeallocationFunction(PreventedBy) || MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator() || MD->isLambdaStaticInvoker() || MD->isOverloadedOperator()) return true; return false; } // Handle function tempates in a class, which are not iterated throught // CXXRecordDecl::method_iterator. // For example: // class A { template void foo(T p) {} }; void RenameCXXMethod::handleOneMemberTemplateFunction( const CXXMethodDecl *MD) { // we could have template constructors if (isSpecialCXXMethod(MD)) return; const FunctionTemplateDecl *FTD = MD->getDescribedFunctionTemplate(); if (!FTD) return; const CXXRecordDecl *CanonicalRD = MD->getParent()->getCanonicalDecl(); CXXRecordDeclToNumMap::iterator I = NumMemberFunctions.find(CanonicalRD); TransAssert((I != NumMemberFunctions.end()) && "Cannot find class!"); unsigned int NumFuns = I->second; NumFuns++; addOneMethodName(MD, NumFuns); NumMemberFunctions[CanonicalRD] = NumFuns; } // handle UnresolvedLookupExpr: // class A { // template static int foo(T, int) { // foo(0, 0); // } // }; // or UnresolvedMemberExpr: // class A { // template < typename T > void foo (T) { foo (0); } // }; void RenameCXXMethod::rewriteOverloadExpr(const OverloadExpr *OE) { const FunctionDecl *FD = getFunctionDeclFromOverloadExpr(OE); if (!FD) return; const CXXMethodDecl *MD = dyn_cast(FD); TransAssert(MD && "Invalid CXXMethodDecl!"); std::string NewName = ""; if (!getMethodNewName(MD, NewName)) return; TransAssert((NewName != "") && "Bad new name!"); if (OE->getQualifier()) { NestedNameSpecifierLoc QualLoc = OE->getQualifierLoc(); RewriteHelper->replaceCXXMethodNameAfterQualifier( &QualLoc, MD, NewName); } else { TheRewriter.ReplaceText(OE->getNameLoc(), MD->getNameAsString().size(), NewName); } } const FunctionDecl* RenameCXXMethod::getFunctionDeclFromOverloadExpr( const OverloadExpr *OE) { const CXXRecordDecl *RD = OE->getNamingClass(); if (!RD) return NULL; DeclarationName DName = OE->getName(); DeclarationName::NameKind K = DName.getNameKind(); if (K == DeclarationName::CXXOperatorName) return NULL; TransAssert((K == DeclarationName::Identifier) && "Not an indentifier!"); DeclContextSet VisitedCtxs; return lookupFunctionDecl(DName, RD, VisitedCtxs); } const FunctionDecl* RenameCXXMethod::getFunctionDeclFromType( const Type *Ty, DeclarationName &DName) { if (Ty->isPointerType() || Ty->isReferenceType()) Ty = getBasePointerElemType(Ty); const FunctionDecl *FD = NULL; if (const CXXRecordDecl *BaseRD = getBaseDeclFromType(Ty)) { DeclContextSet VisitedCtxs; FD = lookupFunctionDecl(DName, BaseRD, VisitedCtxs); } return FD; } const FunctionDecl* RenameCXXMethod::getFunctionDeclFromOverloadTemplate( const CallExpr *CE, const OverloadExpr *OE, DeclarationName &DName) { const FunctionDecl *FD = getFunctionDeclFromOverloadExpr(OE); // FD is not necessary a member function if (!FD) { TransAssert(CurrentFD && "Invalid CurrentFD!"); const DeclContext *Ctx = CurrentFD->getLookupParent(); TransAssert(Ctx && "Bad DeclContext!"); DeclarationName FunName = OE->getName(); DeclContextSet VisitedCtxs; FD = lookupFunctionDecl(FunName, Ctx, VisitedCtxs); if (!FD) return NULL; } const Type *Ty = FD->getReturnType().getTypePtr(); return getFunctionDeclFromType(Ty, DName); } const FunctionDecl* RenameCXXMethod::getFunctionDeclFromReturnType( const CallExpr *CE, DeclarationName &DName) { const Expr *CalleeExpr = CE->getCallee(); TransAssert(CalleeExpr && "NULL CalleeExpr!"); // template class A { // struct B{ // static B& bar() {} // }; // B& foo() {} // void baz() { // foo().bar(); // } // }; // get the return type of foo(). if (const MemberExpr *ME = dyn_cast(CalleeExpr)) { const ValueDecl *VD = ME->getMemberDecl(); const CXXMethodDecl *MD = dyn_cast(VD); if (!MD) return NULL; const Type *Ty = MD->getReturnType().getTypePtr(); return getFunctionDeclFromType(Ty, DName); } else if (const DeclRefExpr *DRE = dyn_cast(CalleeExpr)) { const ValueDecl *VD = DRE->getDecl(); const CXXMethodDecl *MD = dyn_cast(VD); if (!MD) return NULL; const Type *Ty = MD->getReturnType().getTypePtr(); return getFunctionDeclFromType(Ty, DName); } else if (const OverloadExpr *OE = dyn_cast(CalleeExpr)) { return getFunctionDeclFromOverloadTemplate(CE, OE, DName); } else if (const CXXDependentScopeMemberExpr *DE = dyn_cast(CalleeExpr)) { // template class A { // public: // T foo(); // }; // template class B { // public: // A a; // void bar(); // A &return_a() { return a; } // }; // template void bar() { // B b; // T xx = b.return_a().foo(); // } // CallExpr could be invoked via CXXDependentScopeMemberExpr, // then we get the called function (e.g., return_a) via looking up // the base(e.g., b) of CXXDependentScopeMemberExpr const FunctionDecl *FD = getFunctionDecl(DE); if (!FD) return NULL; const Type *Ty = FD->getReturnType().getTypePtr(); // Note that it's not always true that we could get a // non-null function here, e.g.: // template class A { // public: // T foo(); // }; // template class B { // public: // T a; // void bar(); // T &return_a() { return a; } // }; // template void bar() { // B b; // T xx = b.return_a().foo(); // } // here we cannot resolve return_a's return type return getFunctionDeclFromType(Ty, DName); } return NULL; } // could return NULL const FunctionDecl* RenameCXXMethod::getFunctionDecl( const CXXDependentScopeMemberExpr *DE) { if (DE->isImplicitAccess()) return NULL; DeclarationName DName = DE->getMember(); if (DName.getNameKind() == DeclarationName::CXXOperatorName) return NULL; TransAssert((DName.getNameKind() == DeclarationName::Identifier) && "Not an indentifier!"); const Expr *E = DE->getBase(); TransAssert(E && "NULL Base Expr!"); const Expr *BaseE = E->IgnoreParens(); const FunctionDecl *FD = NULL; if (dyn_cast(BaseE)) { TransAssert(CurrentFD && "NULL CurrentFD!"); const DeclContext *Ctx = CurrentFD->getLookupParent(); TransAssert(Ctx && "Bad DeclContext!"); DeclContextSet VisitedCtxs; FD = lookupFunctionDecl(DName, Ctx, VisitedCtxs); TransAssert(FD && "Cannot resolve DName!"); return FD; } // it's not always the case we can get a non-null FD, e.g. // template // struct S // { // static int foo(T t) { return t.bar(); } // }; // here we can't resolve bar() // What should we do? assign a fresh name to this kind of function? if (const DeclRefExpr *DRE = dyn_cast(BaseE)) { FD = getFunctionDeclFromType(DRE->getType().getTypePtr(), DName); return FD; } if (const CallExpr *CE = dyn_cast(BaseE)) { FD = getFunctionDeclFromReturnType(CE, DName); // TransAssert(FD && "Cannot find FunctionDecl!"); return FD; } if (const MemberExpr *ME = dyn_cast(BaseE)) { const Expr *MEBase = ME->getBase(); return getFunctionDeclFromType(MEBase->getType().getTypePtr(), DName); } const Type *Ty = DE->getBaseType().getTypePtr(); if (Ty->isPointerType() || Ty->isReferenceType()) Ty = getBasePointerElemType(Ty); if (const DeclContext *Ctx = getBaseDeclFromType(Ty)) { DeclContextSet VisitedCtxs; return lookupFunctionDecl(DName, Ctx, VisitedCtxs); } return NULL; } void RenameCXXMethod::rewriteCXXDependentScopeMemberExpr( const CXXDependentScopeMemberExpr *DE) { const FunctionDecl *FD = getFunctionDecl(DE); if (!FD) return; const CXXMethodDecl *MD = dyn_cast(FD); TransAssert(MD && "Invalid MD!"); std::string NewName = ""; if (!getMethodNewName(MD, NewName)) return; TransAssert((NewName != "") && "Bad new name!"); if (DE->getQualifier()) { NestedNameSpecifierLoc QualLoc = DE->getQualifierLoc(); RewriteHelper->replaceCXXMethodNameAfterQualifier( &QualLoc, MD, NewName); } else { TheRewriter.ReplaceText(DE->getMemberLoc(), MD->getNameAsString().size(), NewName); } } void RenameCXXMethod::rewriteDependentExpr(const Expr *E) { if (const OverloadExpr *OE = dyn_cast(E)) { rewriteOverloadExpr(OE); return; } if (const CXXDependentScopeMemberExpr *DE = dyn_cast(E)) { rewriteCXXDependentScopeMemberExpr(DE); return; } } const CXXMethodDecl* RenameCXXMethod::getCXXMethodFromMemberFunction( const CXXMethodDecl *MD) { // coud happen, e.g.: // template struct A { int foo(); }; // void bar () { // A a; // a.foo(); <-- here we find foo via getInstantiatedFromMemberFunction // } const FunctionDecl *FD = MD->getInstantiatedFromMemberFunction(); if (FD) { MD = dyn_cast(FD); TransAssert(MD && "bad conversion from FD to MD!"); return MD; } // one more try FD = MD->getTemplateInstantiationPattern(); if (FD) { MD = dyn_cast(FD); TransAssert(MD && "bad conversion from FD to MD!"); return MD; } return NULL; } bool RenameCXXMethod::getMethodNewName(const CXXMethodDecl *MD, std::string &NewName) { const CXXMethodDecl *CanonicalMD = MD->getCanonicalDecl(); llvm::DenseMap::iterator I = NewMethodNames.find(CanonicalMD); if (I == NewMethodNames.end()) { CanonicalMD = getCXXMethodFromMemberFunction(CanonicalMD); I = NewMethodNames.find(CanonicalMD); if (I == NewMethodNames.end()) return false; } NewName = I->second; return true; } void RenameCXXMethod::rewriteFunctionTemplateExplicitInstantiation( const FunctionDecl *FD) { const CXXMethodDecl *MD = dyn_cast(FD); TransAssert(MD && "Not a CXXMethodDecl!"); const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern(); TransAssert(Pattern && "Cannot find Template Pattern!"); const CXXMethodDecl *TmplMD = dyn_cast(Pattern); TransAssert(TmplMD && "Invalid CXXMethodDecl!"); CXXMethodDeclToNameMap::iterator I = NewMethodNames.find(TmplMD->getCanonicalDecl()); TransAssert((I != NewMethodNames.end()) && "Cannot find CXXMethodDecl!"); std::string Name = I->second; I = NewMethodNames.find(MD); TransAssert((I == NewMethodNames.end()) && "Duplicate find CXXMethodDecl?"); SourceLocation Loc = MD->getPointOfInstantiation(); TheRewriter.ReplaceText(Loc, MD->getNameAsString().size(), Name); } // avoid rewriting the content of an implicit instantiated record decl, e.g. // struct A {}; // template class B { // public: // B() { foo(0); } <--- avoid writing the foo of the implicit instantiation // void foo ( int ); // }; // struct C { B<> b; }; // void foo() { new C; } // template B::B() { foo(0); } bool RenameCXXMethod::isExplicit(const CXXMethodDecl *MD) { if (dyn_cast(CurrentFD)) { if (ClassInstantiation) return false; return (InstantiationQueue.size() == 0); } else { if (FunctionInstantiation && MD->isStatic()) return true; return !FunctionInstantiation; } } void RenameCXXMethod::setClassInstantiationFlag(const RecordDecl *RD) { if (const ClassTemplateSpecializationDecl *Spec = dyn_cast(RD)) { TemplateSpecializationKind K = Spec->getSpecializationKind(); if (K == TSK_ExplicitInstantiationDeclaration) { ClassInstantiation = true; return; } } ClassInstantiation = false; } void RenameCXXMethod::setFunctionInstantiationFlag(const FunctionDecl *FD) { TemplateSpecializationKind K = FD->getTemplateSpecializationKind(); if ((K == TSK_ImplicitInstantiation) || (K == TSK_ExplicitInstantiationDeclaration) || (K == TSK_ExplicitInstantiationDefinition)) { FunctionInstantiation = true; } else { FunctionInstantiation = false; } } RenameCXXMethod::~RenameCXXMethod(void) { delete MethodCollectionVisitor; delete RenameVisitor; } cvise-2.3.0/clang_delta/RenameCXXMethod.h000066400000000000000000000114651402162750500201770ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef RENAME_CXX_METHOD_H #define RENAME_CXX_METHOD_H #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class CXXMethodDecl; class CXXRecordDecl; class Expr; class CallExpr; class OverloadExpr; class CXXDependentScopeMemberExpr; class DeclarationName; class FunctionTemplateDecl; class TemplateArgument; class ClassTemplateSpecializationDecl; } namespace llvm { class StringRef; } class RenameCXXMethodCollectionVisitor; class RenameCXXMethodVisitor; class RenameCXXMethod : public Transformation { friend class RenameCXXMethodCollectionVisitor; friend class RenameCXXMethodVisitor; public: RenameCXXMethod(const char *TransName, const char *Desc) : Transformation(TransName, Desc), MethodCollectionVisitor(NULL), RenameVisitor(NULL), CurrentFD(NULL), ClassInstantiation(false), FunctionInstantiation(false), DoRenaming(false), MethodNamePrefix("m_fn"), NumRenamedMethods(0) { } ~RenameCXXMethod(); virtual bool skipCounter() { return true; } private: typedef llvm::DenseMap CXXMethodDeclToNameMap; typedef llvm::DenseMap CXXRecordDeclToNumMap; typedef llvm::SmallPtrSet CXXRecordDeclSet; typedef llvm::SmallPtrSet CXXMethodDeclSet; typedef llvm::SmallVector ClassSpecDeclVector; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneCXXRecordDecl(const clang::CXXRecordDecl *RD); void addOneMethodName(const clang::CXXMethodDecl *MD, unsigned int Num); void addOneInheritedName(const clang::CXXMethodDecl *MD, const clang::CXXMethodDecl *BaseMD); bool isSpecialCXXMethod(const clang::CXXMethodDecl *MD); unsigned int getNumInheritedFunctions(const clang::CXXRecordDecl *RD); void handleOneMemberTemplateFunction(const clang::CXXMethodDecl *MD); void rewriteDependentExpr(const clang::Expr *E); void rewriteOverloadExpr(const clang::OverloadExpr *OE); void rewriteFunctionTemplateExplicitInstantiation( const clang::FunctionDecl *FD); void rewriteCXXDependentScopeMemberExpr( const clang::CXXDependentScopeMemberExpr *DE); bool getMethodNewName(const clang::CXXMethodDecl *MD, std::string &NewName); bool hasValidMethods(); bool isExplicit(const clang::CXXMethodDecl *MD); const clang::FunctionDecl* getFunctionDecl( const clang::CXXDependentScopeMemberExpr *DE); const clang::CXXMethodDecl* getCXXMethodFromMemberFunction( const clang::CXXMethodDecl *MD); const clang::FunctionDecl* getFunctionDeclFromType( const clang::Type *Ty, clang::DeclarationName &DName); const clang::FunctionDecl* getFunctionDeclFromOverloadExpr( const clang::OverloadExpr *OE); const clang::FunctionDecl* getFunctionDeclFromReturnType( const clang::CallExpr *CE, clang::DeclarationName &DName); const clang::FunctionDecl* getFunctionDeclFromOverloadTemplate( const clang::CallExpr *CE, const clang::OverloadExpr *OE, clang::DeclarationName &DName); bool isValidName(const llvm::StringRef &Name); void setClassInstantiationFlag(const clang::RecordDecl *RD); void clearClassInstantiationFlag(void) { ClassInstantiation = false; } void setFunctionInstantiationFlag(const clang::FunctionDecl *FD); void clearFunctionInstantiationFlag(void) { FunctionInstantiation = false; } RenameCXXMethodCollectionVisitor *MethodCollectionVisitor; RenameCXXMethodVisitor *RenameVisitor; const clang::FunctionDecl *CurrentFD; bool ClassInstantiation; bool FunctionInstantiation; bool DoRenaming; const std::string MethodNamePrefix; int NumRenamedMethods; CXXRecordDeclSet VisitedCXXRecordDecls; CXXMethodDeclSet VisitedSpecializedMethods; CXXMethodDeclToNameMap NewMethodNames; CXXRecordDeclToNumMap NumMemberFunctions; ClassSpecDeclVector InstantiationQueue; // Unimplemented RenameCXXMethod(); RenameCXXMethod(const RenameCXXMethod &); void operator=(const RenameCXXMethod &); }; #endif cvise-2.3.0/clang_delta/RenameClass.cpp000066400000000000000000000154621402162750500177750ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RenameClass.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "CommonRenameClassRewriteVisitor.h" #include "TransformationManager.h" using namespace clang; using namespace clang_delta_common_visitor; static const char *DescriptionMsg = "To increase readability, simplify class names to [A - Z] \ (except E, T and Z). Class names from the same hierarchy tree will \ have alphabetical order. For example, we could have a transformed \ code shown as below: \n\ class A {}; \n\ class B : public A {}; \n\ class C : public B {}; \n"; static RegisterTransformation Trans("rename-class", DescriptionMsg); class RenameClassASTVisitor : public RecursiveASTVisitor { public: explicit RenameClassASTVisitor(RenameClass *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: RenameClass *ConsumerInstance; }; class RenameClassRewriteVisitor : public CommonRenameClassRewriteVisitor { public: RenameClassRewriteVisitor(Transformation *Instance, Rewriter *RT, RewriteUtils *Helper, const CXXRecordDecl *CXXRD, const std::string &Name) : CommonRenameClassRewriteVisitor (Instance, RT, Helper, CXXRD, Name) { } }; bool RenameClassASTVisitor::VisitCXXRecordDecl(CXXRecordDecl *CXXRD) { ConsumerInstance->analyzeOneRecordDecl(CXXRD); return true; } void RenameClass::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RenameClassASTVisitor(this); } void RenameClass::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); } if (QueryInstanceOnly) return; if ((ValidInstanceNum + UsedNames.size() > 23)) { TransError = TransMaxClassesError; return; } else if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RewriteVisitor = new RenameClassRewriteVisitor(this, &TheRewriter, RewriteHelper, TheCXXRecordDecl, NewNameStr); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool RenameClass::isReservedName(char C) { return ((C == 'E') || (C == 'T') || (C == 'U')); } void RenameClass::incValidInstance(const CXXRecordDecl *CXXRD) { ValidInstanceNum++; if (ValidInstanceNum != TransformationCounter) return; while (isReservedName(CurrentName) || UsedNames.count(CurrentName)) { if (CurrentName > 'Z') return; CurrentName++; } TheCXXRecordDecl = CXXRD; NewNameStr.assign(1, CurrentName); } void RenameClass::doAnalysis(void) { for (unsigned Level = 0; Level <= MaxInheritanceLevel; ++Level) { CXXRecordDeclSet *RDSet = LevelToRecords[Level]; if (!RDSet) continue; for (CXXRecordDeclSet::const_iterator I = RDSet->begin(), E = RDSet->end(); I != E; ++I) { const CXXRecordDecl *CXXRD = (*I); if (UsedNameDecls.count(CXXRD->getCanonicalDecl())) continue; if (isInIncludedFile(CXXRD)) continue; incValidInstance(CXXRD); } } } bool RenameClass::isValidName(const std::string &Name) { if (Name.size() != 1) return false; char C = Name[0]; return (((C >= 'A') && (C <= 'Z')) && !isReservedName(C)); } void RenameClass::addOneRecordDecl(const CXXRecordDecl *CanonicalRD, unsigned Level) { RecordToLevel[CanonicalRD] = Level; if (Level > MaxInheritanceLevel) MaxInheritanceLevel = Level; CXXRecordDeclSet *RDSet = LevelToRecords[Level]; if (!RDSet) { RDSet = new CXXRecordDeclSet(); TransAssert(RDSet && "Cannot new a CXXRecordDeclSet!"); LevelToRecords[Level] = RDSet; } RDSet->insert(CanonicalRD); std::string RDName = CanonicalRD->getNameAsString(); if (isValidName(RDName)) { char C = RDName[0]; UsedNames.insert(C); UsedNameDecls.insert(CanonicalRD); } } void RenameClass::analyzeOneRecordDecl(const CXXRecordDecl *CXXRD) { if (isSpecialRecordDecl(CXXRD)) return; // Avoid duplication if (dyn_cast(CXXRD)) return; if (CXXRD->getNameAsString().empty()) return; const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (RecordToLevel.find(CanonicalRD) != RecordToLevel.end()) return; if (!CXXRD->hasDefinition()) { addOneRecordDecl(CanonicalRD, 0); return; } // getNumBases dies on the case where CXXRD has no definition. unsigned NumBases = CanonicalRD->getNumBases(); // in some cases, we will encounter a derived classs before // its base class, // namespace NS1 { // class Derived; // class Base {}; // class Derived: public Base { }; // } if (NumBases == 0) { addOneRecordDecl(CanonicalRD, 0); return; } unsigned Level = 0; for (CXXRecordDecl::base_class_const_iterator I = CanonicalRD->bases_begin(), E = CanonicalRD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); // If cannot find CXXRD's base class, then we assume its base class // has the level of 0 if (!Base) continue; const CXXRecordDecl *CanonicalBase = Base->getCanonicalDecl(); if (CanonicalBase == CanonicalRD) continue; unsigned BaseLevel; RecordToInheritanceLevelMap::iterator LI = RecordToLevel.find(CanonicalBase); if (LI == RecordToLevel.end()) { continue; } BaseLevel = (*LI).second; if (BaseLevel > Level) Level = BaseLevel; } Level++; addOneRecordDecl(CanonicalRD, Level); } RenameClass::~RenameClass(void) { for (InheritanceLevelToRecordsMap::iterator I = LevelToRecords.begin(), E = LevelToRecords.end(); I != E; ++I) { delete (*I).second; } delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/RenameClass.h000066400000000000000000000047561402162750500174460ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef RENAME_CLASS_H #define RENAME_CLASS_H #include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "clang/AST/NestedNameSpecifier.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXRecordDecl; class Type; class TemplateSpecializationType; } class RenameClassASTVisitor; class RenameClassRewriteVisitor; class RenameClass : public Transformation { friend class RenameClassASTVisitor; public: RenameClass(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheCXXRecordDecl(NULL), NewNameStr(""), CurrentName('A'), MaxInheritanceLevel(0) { } ~RenameClass(void); private: typedef llvm::DenseMap RecordToInheritanceLevelMap; typedef llvm::SmallPtrSet CXXRecordDeclSet; typedef llvm::DenseMap InheritanceLevelToRecordsMap; typedef llvm::SmallSet NameCharSet; typedef std::set ClassNameSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doAnalysis(void); void analyzeOneRecordDecl(const clang::CXXRecordDecl *CXXRD); void addOneRecordDecl(const clang::CXXRecordDecl *CanonicalRD, unsigned Level); bool isValidName(const std::string &Name); bool isReservedName(char C); void incValidInstance(const clang::CXXRecordDecl *CXXRD); RecordToInheritanceLevelMap RecordToLevel; InheritanceLevelToRecordsMap LevelToRecords; CXXRecordDeclSet UsedNameDecls; NameCharSet UsedNames; RenameClassASTVisitor *CollectionVisitor; RenameClassRewriteVisitor *RewriteVisitor; const clang::CXXRecordDecl *TheCXXRecordDecl; std::string NewNameStr; char CurrentName; unsigned MaxInheritanceLevel; // Unimplemented RenameClass(void); RenameClass(const RenameClass &); void operator=(const RenameClass &); }; #endif cvise-2.3.0/clang_delta/RenameFun.cpp000066400000000000000000000160201402162750500174470ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RenameFun.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Another pass to increase readability of reduced code. \ It renames function names to fn1, fn2, ...\n"; static RegisterTransformation Trans("rename-fun", DescriptionMsg); class RNFunCollectionVisitor : public RecursiveASTVisitor { public: explicit RNFunCollectionVisitor(RenameFun *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitCallExpr(CallExpr *CE); private: RenameFun *ConsumerInstance; }; class RenameFunVisitor : public RecursiveASTVisitor { public: explicit RenameFunVisitor(RenameFun *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitDeclRefExpr(DeclRefExpr *DRE); private: RenameFun *ConsumerInstance; }; bool RNFunCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { // renaming CXXMethodDecl is handled in a seperate pass if (dyn_cast(FD) || FD->isOverloadedOperator()) { return true; } const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (ConsumerInstance->isInIncludedFile(FD) || ConsumerInstance->isInIncludedFile(CanonicalFD)) return true; ConsumerInstance->addFun(CanonicalFD); if (!ConsumerInstance->hasValidPostfix(FD->getNameAsString())) ConsumerInstance->HasValidFuns = true; return true; } bool RNFunCollectionVisitor::VisitCallExpr(CallExpr *CE) { if (ConsumerInstance->isInIncludedFile(CE)) return true; FunctionDecl *FD = CE->getDirectCallee(); // It could happen, e.g., CE could refer to a DependentScopeDeclRefExpr if (!FD || dyn_cast(FD) || FD->isOverloadedOperator()) return true; if (ConsumerInstance->isInIncludedFile(FD)) return true; const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); // This case is handled by VisitFunctionDecl if (CanonicalFD->isDefined()) return true; // It's possible we don't have function definition ConsumerInstance->addFun(CanonicalFD); if (!ConsumerInstance->hasValidPostfix(FD->getNameAsString())) ConsumerInstance->HasValidFuns = true; return true; } bool RenameFunVisitor::VisitFunctionDecl(FunctionDecl *FD) { FunctionDecl *CanonicalDecl = FD->getCanonicalDecl(); if (ConsumerInstance->isInIncludedFile(FD) || ConsumerInstance->isInIncludedFile(CanonicalDecl) || dyn_cast(FD) || FD->isOverloadedOperator()) { return true; } llvm::DenseMap::iterator I = ConsumerInstance->FunToNameMap.find(CanonicalDecl); TransAssert((I != ConsumerInstance->FunToNameMap.end()) && "Cannot find FunctionDecl!"); return ConsumerInstance->RewriteHelper-> replaceFunctionDeclName(FD, (*I).second); } bool RenameFunVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { if (ConsumerInstance->isInIncludedFile(DRE)) return true; ValueDecl *OrigDecl = DRE->getDecl(); FunctionDecl *FD = dyn_cast(OrigDecl); if (!FD || dyn_cast(FD) || FD->isOverloadedOperator() || ConsumerInstance->isInIncludedFile(FD)) return true; if (FD->isTemplateInstantiation()) { FD = FD->getTemplateInstantiationPattern(); } FunctionDecl *CanonicalDecl = FD->getCanonicalDecl(); llvm::DenseMap::iterator I = ConsumerInstance->FunToNameMap.find(CanonicalDecl); TransAssert((I != ConsumerInstance->FunToNameMap.end()) && "Cannot find FunctionDecl!"); ConsumerInstance->TheRewriter.ReplaceText(DRE->getBeginLoc(), FD->getNameAsString().size(), (*I).second); return true; } void RenameFun::Initialize(ASTContext &context) { Transformation::Initialize(context); FunCollectionVisitor = new RNFunCollectionVisitor(this); RenameVisitor = new RenameFunVisitor(this); ValidInstanceNum = 1; } bool RenameFun::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { FunCollectionVisitor->TraverseDecl(*I); } return true; } bool RenameFun::isConsecutiveNumbersFromOne(void) { size_t Sz = AllValidNumbers.size(); if (!Sz) return true; bool hasOne = AllValidNumbers.count(1); if (!hasOne) return false; if (Sz == 1) { return hasOne; } std::set::iterator I = max_element(AllValidNumbers.begin(), AllValidNumbers.end()); return ((*I) == Sz); } bool RenameFun::hasValidFuns(void) { return (HasValidFuns || !isConsecutiveNumbersFromOne()); } void RenameFun::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) { if (hasValidFuns()) ValidInstanceNum = 1; else ValidInstanceNum = 0; return; } if (!hasValidFuns()) { TransError = TransNoValidFunsError; return; } else if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RenameVisitor && "NULL RenameVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RenameVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool RenameFun::isSpecialFun(const std::string &Name) { if ((Name.compare("main") == 0) || (Name.compare("printf") == 0)) return true; else return false; } bool RenameFun::hasValidPostfix(const std::string &Name) { unsigned int Value; // Don't rename special functions if (isSpecialFun(Name)) return true; if (Name.size() <= 2) return false; std::string Prefix = Name.substr(0, 2); if (Prefix != FunNamePrefix) return false; std::string RestStr = Name.substr(2); std::stringstream TmpSS(RestStr); if (!(TmpSS >> Value)) return false; AllValidNumbers.insert(Value); return true; } void RenameFun::addFun(const FunctionDecl *FD) { std::string Name = FD->getNameAsString(); // Skip special functions if (isSpecialFun(Name) || FD->hasAttr()) FunToNameMap[FD] = Name; if (FunToNameMap.find(FD) != FunToNameMap.end()) return; std::stringstream SS; FunNamePostfix++; SS << FunNamePrefix << FunNamePostfix; TransAssert((FunToNameMap.find(FD) == FunToNameMap.end()) && "Duplicated Fun name!"); FunToNameMap[FD] = SS.str(); } RenameFun::~RenameFun(void) { delete FunCollectionVisitor; delete RenameVisitor; } cvise-2.3.0/clang_delta/RenameFun.h000066400000000000000000000035471402162750500171260ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef RENAME_FUN_H #define RENAME_FUN_H #include #include #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; } class RNFunCollectionVisitor; class RenameFunVisitor; class RenameFun : public Transformation { friend class RNFunCollectionVisitor; friend class RenameFunVisitor; public: RenameFun(const char *TransName, const char *Desc) : Transformation(TransName, Desc), FunCollectionVisitor(NULL), RenameVisitor(NULL), FunNamePrefix("fn"), FunNamePostfix(0), HasValidFuns(false) { } ~RenameFun(void); virtual bool skipCounter(void) { return true; } private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool hasValidPostfix(const std::string &Name); void addFun(const clang::FunctionDecl *FD); bool isConsecutiveNumbersFromOne(void); bool isSpecialFun(const std::string &Name); bool hasValidFuns(void); RNFunCollectionVisitor *FunCollectionVisitor; RenameFunVisitor *RenameVisitor; llvm::DenseMap FunToNameMap; std::set AllValidNumbers; const std::string FunNamePrefix; unsigned int FunNamePostfix; bool HasValidFuns; // Unimplemented RenameFun(void); RenameFun(const RenameFun &); void operator=(const RenameFun &); }; #endif cvise-2.3.0/clang_delta/RenameParam.cpp000066400000000000000000000161001402162750500177560ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RenameParam.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Another pass to increase readability of reduced code. \ It renames function parameters to p1, p2, ...\n"; static RegisterTransformation Trans("rename-param", DescriptionMsg); class ExistingVarCollectionVisitor : public RecursiveASTVisitor { public: explicit ExistingVarCollectionVisitor(RenameParam *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); private: RenameParam *ConsumerInstance; }; class RenameParamVisitor : public RecursiveASTVisitor { public: explicit RenameParamVisitor(RenameParam *Instance) : Rewritten (false), ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool Rewritten; private: RenameParam *ConsumerInstance; llvm::DenseMap ParamNameMap; }; bool ExistingVarCollectionVisitor::VisitVarDecl(VarDecl *VD) { if (ConsumerInstance->isInIncludedFile(VD)) return true; ParmVarDecl *PD = dyn_cast(VD); if (PD) { ConsumerInstance->validateParam(PD); return true; } VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (CanonicalVD->isLocalVarDecl()) { ConsumerInstance->addLocalVar(VD); } else { ConsumerInstance->addGlobalVar(VD); } return true; } bool RenameParamVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || (FD->param_size() == 0)) return true; FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); unsigned int CurrPostfix = 0; ParamNameMap.clear(); for(FunctionDecl::param_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { CurrPostfix++; ParmVarDecl *PD = (*I); if (PD->getNameAsString().empty()) continue; CurrPostfix = ConsumerInstance->validatePostfix(CanonicalFD, CurrPostfix); std::stringstream TmpSS; TmpSS << ConsumerInstance->ParamNamePrefix << CurrPostfix; if (PD->getNameAsString().compare(TmpSS.str()) != 0) Rewritten = true; ConsumerInstance->RewriteHelper->replaceVarDeclName(PD, TmpSS.str()); ParamNameMap[*I] = TmpSS.str(); } return true; } bool RenameParamVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { if (ConsumerInstance->isInIncludedFile(DRE)) return true; ValueDecl *OrigDecl = DRE->getDecl(); ParmVarDecl *PD = dyn_cast(OrigDecl); if (!PD || ConsumerInstance->isInIncludedFile(PD)) return true; llvm::DenseMap::iterator I = ParamNameMap.find(PD); if (I == ParamNameMap.end()) return true; return ConsumerInstance->RewriteHelper->replaceExpr(DRE, (*I).second); } void RenameParam::Initialize(ASTContext &context) { Transformation::Initialize(context); VarCollectionVisitor = new ExistingVarCollectionVisitor(this); RenameVisitor = new RenameParamVisitor(this); ValidInstanceNum = 1; } void RenameParam::HandleTranslationUnit(ASTContext &Ctx) { VarCollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) { if (!HasValidParams) ValidInstanceNum = 0; return; } if (!HasValidParams) { TransError = TransNoValidParamsError; return; } else if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RenameVisitor && "NULL RenameVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RenameVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; else if (!RenameVisitor->Rewritten) TransError = TransNoTextModificationError; } bool RenameParam::getPostfixValue(const std::string &Name, unsigned int &Value) { // It's an unamed parameter, we skip it if (Name.size() == 0) return true; if (Name.size() == 1) return false; std::string Prefix = Name.substr(0, 1); if (Prefix != ParamNamePrefix) return false; std::string RestStr = Name.substr(1); std::stringstream TmpSS(RestStr); if (!(TmpSS >> Value)) return false; return true; } void RenameParam::validateParam(ParmVarDecl *PD) { unsigned int Value; if (PD->isReferenced() && !getPostfixValue(PD->getNameAsString(), Value)) HasValidParams = true; } void RenameParam::addGlobalVar(VarDecl *VD) { unsigned int PostValue; if (!getPostfixValue(VD->getNameAsString(), PostValue)) return; ExistingGlobalVars.insert(PostValue); } void RenameParam::addLocalVar(VarDecl *VD) { unsigned int PostValue; if (!getPostfixValue(VD->getNameAsString(), PostValue)) return; DeclContext *Ctx = VD->getDeclContext(); FunctionDecl *FD = dyn_cast(Ctx); TransAssert(FD && "Bad function declaration!"); FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); ExistingNumberSet *CurrSet; llvm::DenseMap::iterator I = FunExistingVarsMap.find(CanonicalFD); if (I == FunExistingVarsMap.end()) { CurrSet = new ExistingNumberSet(); FunExistingVarsMap[CanonicalFD] = CurrSet; } else { CurrSet = (*I).second; } CurrSet->insert(PostValue); } bool RenameParam::isValidPostfix(ExistingNumberSet *LocalSet, unsigned int Postfix) { if (ExistingGlobalVars.count(Postfix)) return false; if (!LocalSet) return true; return !LocalSet->count(Postfix); } unsigned int RenameParam::validatePostfix(FunctionDecl *FD, unsigned int CurrPostfix) { int MaxIteration = 0; ExistingNumberSet *LocalNumberSet = NULL; llvm::DenseMap::iterator I = FunExistingVarsMap.find(FD); if (I != FunExistingVarsMap.end()) { LocalNumberSet = (*I).second; MaxIteration += static_cast(LocalNumberSet->size()); } MaxIteration += static_cast(ExistingGlobalVars.size()); while (!isValidPostfix(LocalNumberSet, CurrPostfix)) { CurrPostfix++; MaxIteration--; TransAssert((MaxIteration >= 0) && "Bad Postfix!"); } return CurrPostfix; } RenameParam::~RenameParam(void) { delete VarCollectionVisitor; delete RenameVisitor; for (llvm::DenseMap::iterator I = FunExistingVarsMap.begin(), E = FunExistingVarsMap.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/RenameParam.h000066400000000000000000000041201402162750500174220ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef RENAME_PARAM_H #define RENAME_PARAM_H #include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class ParmVarDecl; } class ExistingVarCollectionVisitor; class RenameParamVisitor; class RenameParam : public Transformation { friend class ExistingVarCollectionVisitor; friend class RenameParamVisitor; public: RenameParam(const char *TransName, const char *Desc) : Transformation(TransName, Desc), VarCollectionVisitor(NULL), RenameVisitor(NULL), ParamNamePrefix("p"), HasValidParams(false) { } ~RenameParam(void); virtual bool skipCounter(void) { return true; } private: typedef llvm::SmallSet ExistingNumberSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addGlobalVar(clang::VarDecl *VD); void addLocalVar(clang::VarDecl *VD); bool getPostfixValue(const std::string &Name, unsigned int &Value); bool isValidPostfix(ExistingNumberSet *LocalSet, unsigned int Postfix); unsigned int validatePostfix(clang::FunctionDecl *FD, unsigned int CurrPostfix); void validateParam(clang::ParmVarDecl *PD); ExistingVarCollectionVisitor *VarCollectionVisitor; RenameParamVisitor *RenameVisitor; llvm::DenseMap FunExistingVarsMap; ExistingNumberSet ExistingGlobalVars; const std::string ParamNamePrefix; bool HasValidParams; // Unimplemented RenameParam(void); RenameParam(const RenameParam &); void operator=(const RenameParam &); }; #endif cvise-2.3.0/clang_delta/RenameVar.cpp000066400000000000000000000140361402162750500174540ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RenameVar.h" #include #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "To increase readability, rename global and local variables \ to a, b, ..., z. The transformation returns with error message \ if there are more than 26 different variables. \n"; static RegisterTransformation Trans("rename-var", DescriptionMsg); class RNVCollectionVisitor : public RecursiveASTVisitor { public: explicit RNVCollectionVisitor(RenameVar *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); private: RenameVar *ConsumerInstance; }; class RenameVarVisitor : public RecursiveASTVisitor { public: explicit RenameVarVisitor(RenameVar *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitDeclRefExpr(DeclRefExpr *DRE); private: RenameVar *ConsumerInstance; }; bool RNVCollectionVisitor::VisitVarDecl(VarDecl *VD) { if (ConsumerInstance->isInIncludedFile(VD)) return true; ParmVarDecl *PV = dyn_cast(VD); // Skip parameters if (PV) return true; VarDecl *CanonicalVD = VD->getCanonicalDecl(); ConsumerInstance->addVar(CanonicalVD); return true; } bool RenameVarVisitor::VisitVarDecl(VarDecl *VD) { VarDecl *CanonicalDecl = VD->getCanonicalDecl(); llvm::DenseMap::iterator I = ConsumerInstance->VarToNameMap.find(CanonicalDecl); if (I == ConsumerInstance->VarToNameMap.end()) return true; return ConsumerInstance->RewriteHelper->replaceVarDeclName(VD, (*I).second); } bool RenameVarVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { ValueDecl *OrigDecl = DRE->getDecl(); VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return true; VarDecl *CanonicalDecl = VD->getCanonicalDecl(); llvm::DenseMap::iterator I = ConsumerInstance->VarToNameMap.find(CanonicalDecl); if (I == ConsumerInstance->VarToNameMap.end()) return true; // We can visit the same DRE twice from an InitListExpr, i.e., // through InitListExpr's semantic form and syntactic form. if (ConsumerInstance->VisitedDREs.count(DRE)) return true; ConsumerInstance->VisitedDREs.insert(DRE); return ConsumerInstance->RewriteHelper->replaceExpr(DRE, (*I).second); } void RenameVar::Initialize(ASTContext &context) { Transformation::Initialize(context); VarCollectionVisitor = new RNVCollectionVisitor(this); RenameVisitor = new RenameVarVisitor(this); for (char C = 'z'; C >= 'a'; C--) { AvailableNames.push_back(C); } ValidInstanceNum = 1; } bool RenameVar::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { VarCollectionVisitor->TraverseDecl(*I); } return true; } void RenameVar::HandleTranslationUnit(ASTContext &Ctx) { unsigned int NumNames = AvailableNames.size(); unsigned int NumVars = ValidVars.size(); if (NumVars == 0) { ValidInstanceNum = 0; } else if (NumVars > NumNames) { // TEMP: currently not to rename vars in C++ files if there are // more than 26 global or local vars if (TransformationManager::isCXXLangOpt() || allValidNames()) { ValidInstanceNum = 0; } else { NumNames = NumVars; } } if (QueryInstanceOnly) { return; } if (NumVars > NumNames) { TransError = TransMaxVarsError; return; } else if (NumVars == 0) { TransError = TransNoValidVarsError; return; } else if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RenameVisitor && "NULL RenameVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); collectVars(); RenameVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void RenameVar::addVar(VarDecl *VD) { std::string Name = VD->getNameAsString(); if (Name.size() > 1) { ValidVars.push_back(VD); return; } char C = Name[0]; if ((C < 'a') || (C > 'z')) return; SmallVector::iterator I = std::find(AvailableNames.begin(), AvailableNames.end(), C); // It could be the case where C has been erased, e.g., // two variables from different scopes have the same name if (I == AvailableNames.end()) return; AvailableNames.erase(I); } bool RenameVar::allValidNames(void) { for (std::vector::iterator I = ValidVars.begin(), E = ValidVars.end(); I != E; ++I) { VarDecl *VD = (*I); std::string Name = VD->getNameAsString(); if (Name.size() == 1) { char C = Name[0]; if ((C < 'a') || (C > 'z')) return false; } else { std::stringstream TmpSS(Name.substr(1)); unsigned int Value; if (!(TmpSS >> Value)) return false; } } return true; } void RenameVar::collectVars(void) { unsigned Count = 1; for (std::vector::iterator I = ValidVars.begin(), E = ValidVars.end(); I != E; ++I) { VarDecl *VD = (*I); if (AvailableNames.size()) { char Name = AvailableNames.back(); AvailableNames.pop_back(); VarToNameMap[VD] = std::string(1, Name); } else { std::stringstream TmpSS; TmpSS << RenamePrefix << Count; VarToNameMap[VD] = TmpSS.str(); Count++; } } } RenameVar::~RenameVar(void) { delete VarCollectionVisitor; delete RenameVisitor; } cvise-2.3.0/clang_delta/RenameVar.h000066400000000000000000000033511402162750500171170ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef RENAME_VAR_H #define RENAME_VAR_H #include #include #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class VarDecl; } class RNVCollectionVisitor; class RenameVarVisitor; class RenameVar : public Transformation { friend class RNVCollectionVisitor; friend class RenameVarVisitor; public: RenameVar(const char *TransName, const char *Desc) : Transformation(TransName, Desc), VarCollectionVisitor(NULL), RenameVisitor(NULL), RenamePrefix('t') { } ~RenameVar(void); virtual bool skipCounter(void) { return true; } private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addVar(clang::VarDecl *VD); bool allValidNames(); void collectVars(void); RNVCollectionVisitor *VarCollectionVisitor; RenameVarVisitor *RenameVisitor; char RenamePrefix; std::vector ValidVars; llvm::SmallVector AvailableNames; llvm::DenseMap VarToNameMap; llvm::SmallPtrSet VisitedDREs; // Unimplemented RenameVar(void); RenameVar(const RenameVar &); void operator=(const RenameVar &); }; #endif cvise-2.3.0/clang_delta/ReplaceArrayAccessWithIndex.cpp000066400000000000000000000074421402162750500231170ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2016, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceArrayAccessWithIndex.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include using namespace clang; static const char *Description = "Replace array accesses with the index expression."; static RegisterTransformation Trans("replace-array-access-with-index", Description); class ReplaceArrayAccessWithIndex::IndexCollector : public RecursiveASTVisitor { public: explicit IndexCollector(ReplaceArrayAccessWithIndex *instance); bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); private: const VarDecl *getVarDeclFromExpr(const Expr *E); ReplaceArrayAccessWithIndex *ConsumerInstance; }; ReplaceArrayAccessWithIndex::IndexCollector::IndexCollector( ReplaceArrayAccessWithIndex *instance) : ConsumerInstance(instance) { // No further initialization needed. } bool ReplaceArrayAccessWithIndex::IndexCollector::VisitArraySubscriptExpr( ArraySubscriptExpr *ASE) { // Skip expressions in included files. if (ConsumerInstance->isInIncludedFile(ASE)) return true; const VarDecl *BaseVD = getVarDeclFromExpr(ASE->getBase()); if (!BaseVD) return true; ArrayType const *ArrayTy = dyn_cast(BaseVD->getType().getTypePtr()); // Only apply the transformation to one-dimensional arrays of scalars. if (!ArrayTy || !ArrayTy->getElementType().getTypePtr()->isScalarType()) return true; ConsumerInstance->ASEs.push_back(ASE); ConsumerInstance->ValidInstanceNum++; return true; } const VarDecl *ReplaceArrayAccessWithIndex::IndexCollector::getVarDeclFromExpr( const Expr *E) { TransAssert(E && "NULL Expr!"); const DeclRefExpr *DRE = dyn_cast(E->IgnoreParenCasts()); if (!DRE) return NULL; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return NULL; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); return CanonicalVD; } ReplaceArrayAccessWithIndex::~ReplaceArrayAccessWithIndex(void) { delete Collector; } void ReplaceArrayAccessWithIndex::Initialize(clang::ASTContext &context) { Transformation::Initialize(context); Collector = new IndexCollector(this); } void ReplaceArrayAccessWithIndex::HandleTranslationUnit(clang::ASTContext &Ctx) { TransAssert(Collector && "NULL Collector"); Collector->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doRewrite(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceArrayAccessWithIndex::doRewrite(void) { ArraySubscriptExpr const *ASE = ASEs[TransformationCounter - 1]; Expr const *Idx = ASE->getIdx(); TransAssert(Idx && "Bad Idx!"); std::string IdxStr; RewriteHelper->getExprString(Idx, IdxStr); QualType ASEType = ASE->getType().getCanonicalType(); QualType IdxType = Idx->getType().getCanonicalType(); if (ASEType != IdxType) { IdxStr = std::string("(") + ASEType.getAsString() + std::string(")")+ std::string("(") + IdxStr + std::string(")"); } RewriteHelper->replaceExpr(ASE, IdxStr); } cvise-2.3.0/clang_delta/ReplaceArrayAccessWithIndex.h000066400000000000000000000023211402162750500225530ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_ARRAY_ACCESS_WITH_INDEX #define REPLACE_ARRAY_ACCESS_WITH_INDEX #include "Transformation.h" class ReplaceArrayAccessWithIndex : public Transformation { public: ReplaceArrayAccessWithIndex(const char *TransName, const char *Desc) : Transformation(TransName, Desc) , Collector(NULL) { } ~ReplaceArrayAccessWithIndex(void); private: class IndexCollector; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doRewrite(void); IndexCollector *Collector; std::vector ASEs; // Unimplemented ReplaceArrayAccessWithIndex(void); ReplaceArrayAccessWithIndex(const ReplaceArrayAccessWithIndex &); void operator=(const ReplaceArrayAccessWithIndex &); }; #endif /* Local Variables: mode: c++ fill-column: 79 End: */ cvise-2.3.0/clang_delta/ReplaceArrayIndexVar.cpp000066400000000000000000000162301402162750500216050ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceArrayIndexVar.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Looking for the pattern like below: \n\ for (...;...; i++) { \n\ a[i]; \n\ } \n\ if is less than 15, then replace a[i] with a[0] ... a[num-1]"; static RegisterTransformation Trans("replace-array-index-var", DescriptionMsg); typedef llvm::SmallPtrSet ArraySubscriptExprSet; typedef llvm::DenseMap VarDeclToASESetMap; typedef llvm::DenseMap ArrayVarsToSizeMap; class ReplaceArrayIndexVarCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceArrayIndexVarCollectionVisitor(ReplaceArrayIndexVar *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitForStmt(ForStmt *FS); private: ReplaceArrayIndexVar *ConsumerInstance; }; class ArraySubscriptExprCollectionVisitor : public RecursiveASTVisitor { public: ArraySubscriptExprCollectionVisitor(const VarDecl *VD, ArrayVarsToSizeMap &Vars, VarDeclToASESetMap &Map) : IdxVD(VD), CstArrayVars(Vars), ASEMap(Map) { } ~ArraySubscriptExprCollectionVisitor(); bool VisitArraySubscriptExpr(ArraySubscriptExpr *ASE); private: const VarDecl *getVarDeclFromExpr( const Expr *E); const VarDecl *IdxVD; ArrayVarsToSizeMap &CstArrayVars; VarDeclToASESetMap &ASEMap; }; bool ReplaceArrayIndexVarCollectionVisitor::VisitVarDecl(VarDecl *VD) { const VarDecl *CanonicalVD = VD->getCanonicalDecl(); if (ConsumerInstance->CstArrayVars[CanonicalVD]) return true; const Type *Ty = CanonicalVD->getType().getTypePtr(); const ConstantArrayType *CstArrayTy = dyn_cast(Ty); if (!CstArrayTy) return true; // skip multi-dimension arrays const Type *ElemTy = CstArrayTy->getElementType().getTypePtr(); if (dyn_cast(ElemTy)) return true; llvm::APInt APSz = CstArrayTy->getSize(); unsigned Sz = (unsigned int)(*APSz.getRawData()); if (Sz <= ConsumerInstance->MaxSize) ConsumerInstance->CstArrayVars[CanonicalVD] = Sz; return true; } bool ReplaceArrayIndexVarCollectionVisitor::VisitForStmt(ForStmt *FS) { if (ConsumerInstance->isInIncludedFile(FS)) return true; const Expr *Inc = FS->getInc(); if (!Inc) return true; Stmt *Body = FS->getBody(); if (!Body || dyn_cast(Body)) return true; const DeclRefExpr *DRE; if (const BinaryOperator *BO = dyn_cast(Inc->IgnoreParenCasts())) { if (!BO || !BO->isAssignmentOp()) return true; const Expr *Lhs = BO->getLHS()->IgnoreParenCasts(); DRE = dyn_cast(Lhs); } else if (const UnaryOperator *UO = dyn_cast(Inc->IgnoreParenCasts())) { if (!UO || !UO->isIncrementDecrementOp()) return true; const Expr *SubE = UO->getSubExpr()->IgnoreParenCasts(); DRE = dyn_cast(SubE); } else { return true; } if (!DRE) return true; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return true; VarDeclToASESetMap ASEMap; ArraySubscriptExprCollectionVisitor ASEVisitor(VD->getCanonicalDecl(), ConsumerInstance->CstArrayVars, ASEMap); ASEVisitor.TraverseStmt(Body); for (VarDeclToASESetMap::iterator I = ASEMap.begin(), E = ASEMap.end(); I != E; ++I) { const VarDecl *CurrVD = (*I).first; ArraySubscriptExprSet *ESet = (*I).second; if (!ESet) continue; TransAssert(ConsumerInstance->CstArrayVars.count(CurrVD) && "Cannot find CurrVD!"); unsigned Sz = ConsumerInstance->CstArrayVars[CurrVD]; for (unsigned Idx = 0; Idx < Sz; Idx++) { ConsumerInstance->ValidInstanceNum++; if (!ConsumerInstance->TheASESet && (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter)) { ConsumerInstance->TheASESet = new ArraySubscriptExprSet(*ESet); ConsumerInstance->CurrIdx = Idx; } } } return true; } const VarDecl *ArraySubscriptExprCollectionVisitor::getVarDeclFromExpr( const Expr *E) { TransAssert(E && "NULL Expr!"); const DeclRefExpr *DRE = dyn_cast(E->IgnoreParenCasts()); if (!DRE) return NULL; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); if (!VD) return NULL; const VarDecl *CanonicalVD = VD->getCanonicalDecl(); return CanonicalVD; } bool ArraySubscriptExprCollectionVisitor::VisitArraySubscriptExpr( ArraySubscriptExpr *ASE) { const VarDecl *BaseVD = getVarDeclFromExpr(ASE->getBase()); if (!BaseVD || !CstArrayVars[BaseVD]) return true; const VarDecl *VD = getVarDeclFromExpr(ASE->getIdx()); if (!VD || (VD != IdxVD)) return true; ArraySubscriptExprSet *ESet = ASEMap[BaseVD]; if (!ESet) { ESet = new ArraySubscriptExprSet(); ASEMap[BaseVD] = ESet; } ESet->insert(ASE); return true; } ArraySubscriptExprCollectionVisitor::~ArraySubscriptExprCollectionVisitor(void) { for (VarDeclToASESetMap::iterator I = ASEMap.begin(), E = ASEMap.end(); I != E; ++I) { ArraySubscriptExprSet *Set = (*I).second; delete Set; } } void ReplaceArrayIndexVar::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceArrayIndexVarCollectionVisitor(this); } void ReplaceArrayIndexVar::HandleTranslationUnit(ASTContext &Ctx) { TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doRewrite(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceArrayIndexVar::doRewrite(void) { for (ArraySubscriptExprSet::iterator I = TheASESet->begin(), E = TheASESet->end(); I != E; ++I) { const ArraySubscriptExpr *ASE = (*I); const Expr *Idx = ASE->getIdx(); TransAssert(Idx && "Bad Idx!"); std::stringstream TmpSS; TmpSS << CurrIdx; RewriteHelper->replaceExpr(Idx, TmpSS.str()); } } ReplaceArrayIndexVar::~ReplaceArrayIndexVar(void) { delete CollectionVisitor; delete TheASESet; } cvise-2.3.0/clang_delta/ReplaceArrayIndexVar.h000066400000000000000000000031751402162750500212560ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_ARRAY_INDEX_VAR_H #define REPLACE_ARRAY_INDEX_VAR_H #include "Transformation.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; } class ReplaceArrayIndexVarCollectionVisitor; class ReplaceArrayIndexVar : public Transformation { friend class ReplaceArrayIndexVarCollectionVisitor; public: ReplaceArrayIndexVar(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), MaxSize(15), TheASESet(NULL), CurrIdx(0) { } ~ReplaceArrayIndexVar(void); private: typedef llvm::SmallPtrSet ArraySubscriptExprSet; typedef llvm::DenseMap ArrayVarsToSizeMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doRewrite(void); ArrayVarsToSizeMap CstArrayVars; ReplaceArrayIndexVarCollectionVisitor *CollectionVisitor; const unsigned MaxSize; ArraySubscriptExprSet *TheASESet; unsigned CurrIdx; // Unimplemented ReplaceArrayIndexVar(void); ReplaceArrayIndexVar(const ReplaceArrayIndexVar &); void operator=(const ReplaceArrayIndexVar &); }; #endif cvise-2.3.0/clang_delta/ReplaceCallExpr.cpp000066400000000000000000000412661402162750500206070ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceCallExpr.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Replace a CallExpr with a return expression from \ this callee's body. The transformation fires only \ if the components of the return expression are one \ of the following: \n\ * global variables \n\ * parameters \n\ * constants \n\ If a callee has several return statements, all of them \ will be exercised separately, i.e., the transformation \ will choose one for each iteration. \ This pass is unsound because the side-effect on globals \ and parameters caused by callees are not captured. \n"; static RegisterTransformation Trans("replace-callexpr", DescriptionMsg); class ReplaceCallExprVisitor : public RecursiveASTVisitor { public: explicit ReplaceCallExprVisitor(ReplaceCallExpr *Instance) : ConsumerInstance(Instance), CurrentReturnStmt(NULL) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitCallExpr(CallExpr *CE); bool VisitReturnStmt(ReturnStmt *RS); private: bool isValidReturnStmt(ReturnStmt *RS); bool isValidExpr(const Expr *E); bool isValidNamedDecl(const NamedDecl *ND); bool isValidValueDecl(const ValueDecl *VD); bool isValidDeclRefExpr(const DeclRefExpr *DE); ReplaceCallExpr *ConsumerInstance; ReturnStmt *CurrentReturnStmt; }; class ExprCountVisitor : public RecursiveASTVisitor { public: ExprCountVisitor(void) : NumExprs(0) { } unsigned int getNumExprs(void) { return NumExprs; } void resetNumExprs(void) { NumExprs = 0; } bool VisitExpr(Expr *E); private: unsigned int NumExprs; }; bool ExprCountVisitor::VisitExpr(Expr *E) { NumExprs++; return true; } bool ReplaceCallExprVisitor::isValidReturnStmt(ReturnStmt *RS) { Expr *E = RS->getRetValue(); if (!E) return false; const Type *T = E->getType().getTypePtr(); if (T->isVoidType()) return false; CurrentReturnStmt = RS; bool RV = isValidExpr(E); CurrentReturnStmt = NULL; return RV; } bool ReplaceCallExprVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (FD->isThisDeclarationADefinition()) { ConsumerInstance->CurrentFD = FD; } else { // We skip locally declared function decls. if (FD->getLexicalParent()->getDeclKind() != Decl::Function) ConsumerInstance->CurrentFD = NULL; } return true; } bool ReplaceCallExprVisitor::VisitReturnStmt(ReturnStmt *RS) { TransAssert(ConsumerInstance->CurrentFD && "Bad CurrentFD!"); if (!isValidReturnStmt(RS)) return true; ConsumerInstance->addOneReturnStmt(RS); return true; } bool ReplaceCallExprVisitor::VisitCallExpr(CallExpr *CE) { if (ConsumerInstance->isInIncludedFile(CE)) return true; FunctionDecl *FD = CE->getDirectCallee(); if (!FD) return true; const Type *T; // Because CE->getCallReturnType() fails on builtin functions, // try to get returntype from FD (probably not really accurate thought) if (FD->getBuiltinID()) T = FD->getReturnType().getTypePtr(); else T = CE->getCallReturnType(FD->getASTContext()).getTypePtr(); if (T->isVoidType()) return true; ConsumerInstance->AllCallExprs.push_back(CE); return true; } bool ReplaceCallExprVisitor::isValidValueDecl(const ValueDecl *ValueD) { const VarDecl *VarD = dyn_cast(ValueD); if (!VarD || VarD->isLocalVarDecl()) return false; if (VarD->hasGlobalStorage()) return true; return (dyn_cast(VarD) != NULL); } bool ReplaceCallExprVisitor::isValidNamedDecl(const NamedDecl *ND) { const DeclContext *Ctx = ND->getDeclContext(); const FunctionDecl *FD = dyn_cast(Ctx); // local named decl if (FD) return false; const ValueDecl *VD = dyn_cast(ND); return (VD && isValidValueDecl(VD)); } bool ReplaceCallExprVisitor::isValidDeclRefExpr(const DeclRefExpr *DE) { const ValueDecl *OrigDecl = DE->getDecl(); bool RV = isValidValueDecl(OrigDecl); if (!RV) return false; if (!dyn_cast(OrigDecl)) return RV; ConsumerInstance->addOneParmRef(CurrentReturnStmt, DE); return RV; } bool ReplaceCallExprVisitor::isValidExpr(const Expr *E) { TransAssert(E && "NULL Expr!"); switch(E->getStmtClass()) { case Expr::FloatingLiteralClass: case Expr::StringLiteralClass: case Expr::IntegerLiteralClass: case Expr::GNUNullExprClass: case Expr::CharacterLiteralClass: // Fall-through return true; case Expr::ParenExprClass: return isValidExpr(cast(E)->getSubExpr()); case Expr::ImplicitCastExprClass: case Expr::CStyleCastExprClass: // Fall-through return isValidExpr(cast(E)->getSubExpr()); case Expr::UnaryOperatorClass: return isValidExpr(cast(E)->getSubExpr()); case Expr::BinaryOperatorClass: { const BinaryOperator *BE = cast(E); return isValidExpr(BE->getLHS()) && isValidExpr(BE->getRHS()); } case Expr::BinaryConditionalOperatorClass: { const BinaryConditionalOperator *BE = cast(E); return isValidExpr(BE->getCommon()) && isValidExpr(BE->getFalseExpr()); } case Expr::ConditionalOperatorClass: { const ConditionalOperator *CE = cast(E); return (isValidExpr(CE->getCond()) && isValidExpr(CE->getTrueExpr()) && isValidExpr(CE->getFalseExpr())); } case Expr::SizeOfPackExprClass: { const SizeOfPackExpr *SE = cast(E); NamedDecl *ND = SE->getPack(); return isValidNamedDecl(ND); } case Expr::OffsetOfExprClass: { const OffsetOfExpr *OE = cast(E); for (unsigned Idx = 0; Idx < OE->getNumExpressions(); ++Idx) { if (!isValidExpr(OE->getIndexExpr(Idx))) return false; } return true; } case Expr::MemberExprClass: { const MemberExpr *ME = cast(E); return isValidExpr(ME->getBase()); } case Expr::ArraySubscriptExprClass: { const ArraySubscriptExpr *AE = cast(E); return isValidExpr(AE->getIdx()) && isValidExpr(AE->getBase()); } case Expr::DeclRefExprClass: { const DeclRefExpr *DE = cast(E); return isValidDeclRefExpr(DE); } default: return false; } TransAssert(0 && "Unreachable code!"); return false; } void ReplaceCallExpr::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceCallExprVisitor(this); } void ReplaceCallExpr::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheCallExpr && "NULL TheCallExpr!"); TransAssert(TheReturnStmt && "NULL TheReturnStmt"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); replaceCallExpr(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceCallExpr::addOneReturnStmt(ReturnStmt *RS) { llvm::DenseMap::iterator I = FuncToReturnStmts.find(CurrentFD); ReturnStmtsVector *V; if (I == FuncToReturnStmts.end()) { V = new ReturnStmtsVector(); TransAssert(V); FuncToReturnStmts[CurrentFD] = V; } else { V = (*I).second; } TransAssert((std::find(V->begin(), V->end(), RS) == V->end()) && "Duplicated ReturnStmt!"); V->push_back(RS); } void ReplaceCallExpr::addOneParmRef(ReturnStmt *RS, const DeclRefExpr *DE) { TransAssert(RS && "NULL ReturnStmt!"); llvm::DenseMap::iterator I = ReturnStmtToParmRefs.find(RS); ParmRefsVector *V; if (I == ReturnStmtToParmRefs.end()) { V = new ParmRefsVector(); TransAssert(V); ReturnStmtToParmRefs[RS] = V; } else { V = (*I).second; } TransAssert((std::find(V->begin(), V->end(), DE) == V->end()) && "Duplicated ParmRef!"); V->push_back(DE); } void ReplaceCallExpr::getParmPosVector(ParameterPosVector &PosVector, ReturnStmt *RS, CallExpr *CE) { llvm::DenseMap::iterator RI = ReturnStmtToParmRefs.find(RS); if (RI == ReturnStmtToParmRefs.end()) return; ParmRefsVector *PVector = (*RI).second; FunctionDecl *FD = CE->getDirectCallee(); for (ParmRefsVector::const_iterator PI = PVector->begin(), PE = PVector->end(); PI != PE; ++PI) { const ValueDecl *OrigDecl = (*PI)->getDecl(); const ParmVarDecl *PD = dyn_cast(OrigDecl); unsigned int Pos = 0; for(FunctionDecl::param_const_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { if (PD == (*I)) break; Pos++; } PosVector.push_back(Pos); } } bool ReplaceCallExpr::hasUnmatchedParmArg(const ParameterPosVector &PosVector, CallExpr *CE) { unsigned int ArgNum = CE->getNumArgs(); for (ParameterPosVector::const_iterator I = PosVector.begin(), E = PosVector.end(); I != E; ++I) { if ((*I) >= ArgNum) return true; } return false; } // A heuristic way to check if replacing CallExpr could cause // code bloat. bool ReplaceCallExpr::hasBadEffect(const ParameterPosVector &PosVector, ReturnStmt *RS, CallExpr *CE) { ExprCountVisitor ECVisitor; Expr *RVExpr = RS->getRetValue(); TransAssert(RVExpr && "Bad Return Expr!"); ECVisitor.TraverseStmt(RVExpr); unsigned int RVNumExprs = ECVisitor.getNumExprs(); TransAssert(RVNumExprs && "Bad NumExprs!"); // really conservatively set 5 as a threshold value unsigned int ArgNum = CE->getNumArgs(); if (!ArgNum) return (RVNumExprs > 5); llvm::SmallVector ArgNumExprs; unsigned int Num; unsigned int CallExprsNum = 0; for (unsigned int I = 0; I < ArgNum; ++I) { ECVisitor.TraverseStmt(CE->getArg(I)); Num = ECVisitor.getNumExprs(); TransAssert(Num && "Bad NumExprs!"); ArgNumExprs.push_back(Num); CallExprsNum += Num; } // Adjust the size of RVExpr for (ParameterPosVector::const_iterator I = PosVector.begin(), E = PosVector.end(); I != E; ++I) { unsigned int Pos = (*I); TransAssert((Pos < ArgNum) && "Bad ParmPos!"); Num = ArgNumExprs[Pos]; RVNumExprs += (Num - 1); } return (RVNumExprs > (CallExprsNum + 5)); } void ReplaceCallExpr::doAnalysis(void) { for (SmallVector::iterator CI = AllCallExprs.begin(), CE = AllCallExprs.end(); CI != CE; ++CI) { FunctionDecl *CalleeDecl = (*CI)->getDirectCallee(); TransAssert(CalleeDecl && "Bad CalleeDecl!"); llvm::DenseMap::iterator I = FuncToReturnStmts.find(CalleeDecl); if (I == FuncToReturnStmts.end()) continue; ReturnStmtsVector *RVector = (*I).second; TransAssert(RVector && "NULL RVector!"); for (ReturnStmtsVector::iterator RI = RVector->begin(), RE = RVector->end(); RI != RE; ++RI) { ParameterPosVector PosVector; getParmPosVector(PosVector, *RI, *CI); if (hasUnmatchedParmArg(PosVector, *CI)) continue; if (hasBadEffect(PosVector, *RI, *CI)) continue; ValidInstanceNum++; if (TransformationCounter != ValidInstanceNum) continue; TheCallExpr = (*CI); TheReturnStmt = (*RI); } } } void ReplaceCallExpr::getNewParmRefStr(const DeclRefExpr *DE, std::string &ParmRefStr) { const ValueDecl *OrigDecl = DE->getDecl(); const ParmVarDecl *PD = dyn_cast(OrigDecl); TransAssert(PD && "Bad ParmVarDecl!"); FunctionDecl *FD = TheCallExpr->getDirectCallee(); unsigned int Pos = 0; for(FunctionDecl::param_const_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { TransAssert((Pos < TheCallExpr->getNumArgs()) && "Unmatched Parm and Arg!"); if (PD != (*I)) { Pos++; continue; } const Expr *Arg = TheCallExpr->getArg(Pos)->IgnoreParenImpCasts(); RewriteHelper->getExprString(Arg, ParmRefStr); ParmRefStr = "(" + ParmRefStr + ")"; const Type *ParmT = PD->getType().getTypePtr(); const Type *CanParmT = Context->getCanonicalType(ParmT); const Type *ArgT = Arg->getType().getTypePtr(); const Type *CanArgT = Context->getCanonicalType(ArgT); if (CanParmT != CanArgT) { std::string TypeCastStr = PD->getType().getAsString(); ParmRefStr = "(" + TypeCastStr + ")" + ParmRefStr; } return; } TransAssert(0 && "Unreachable Code!"); } void ReplaceCallExpr::insertParmRef (std::vector< std::pair > &SortedParmRefs, const DeclRefExpr *ParmRef, int Off) { std::pair ParmOffPair(ParmRef, Off); if (SortedParmRefs.empty()) { SortedParmRefs.push_back(ParmOffPair); return; } std::vector< std::pair >::iterator I, E; for(I = SortedParmRefs.begin(), E = SortedParmRefs.end(); I != E; ++I) { int TmpOff = (*I).second; if (Off < TmpOff) break; } if (I == E) SortedParmRefs.push_back(ParmOffPair); else SortedParmRefs.insert(I, ParmOffPair); } void ReplaceCallExpr::sortParmRefsByOffs(const char *StartBuf, llvm::DenseMap &ParmRefToStrMap, std::vector< std::pair > &SortedParmRefs) { for(llvm::DenseMap::iterator I = ParmRefToStrMap.begin(), E = ParmRefToStrMap.end(); I != E; ++I) { const DeclRefExpr *ParmRef = (*I).first; SourceLocation ParmRefLocStart = ParmRef->getBeginLoc(); const char *ParmRefStartBuf = SrcManager->getCharacterData(ParmRefLocStart); int Off = ParmRefStartBuf - StartBuf; TransAssert((Off >= 0) && "Bad Offset!"); insertParmRef(SortedParmRefs, ParmRef, Off); } } void ReplaceCallExpr::replaceParmRefs(std::string &RetStr, const Expr *RetE, llvm::DenseMap &ParmRefToStrMap) { SourceLocation StartLoc = RetE->getBeginLoc(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::vector< std::pair > SortedParmRefs; // Must sort ParmRefs to make Delta value correct sortParmRefsByOffs(StartBuf, ParmRefToStrMap, SortedParmRefs); int Delta = 0; for(std::vector< std::pair >::iterator I = SortedParmRefs.begin(), E = SortedParmRefs.end(); I != E; ++I) { const DeclRefExpr *ParmRef = (*I).first; const ValueDecl *OrigDecl = ParmRef->getDecl(); size_t ParmRefSize = OrigDecl->getNameAsString().size(); int Off = (*I).second + Delta; std::string NewStr = ParmRefToStrMap[ParmRef]; RetStr.replace(Off, ParmRefSize, NewStr); Delta += (NewStr.size() - ParmRefSize); } } void ReplaceCallExpr::replaceCallExpr(void) { Expr *RetE = TheReturnStmt->getRetValue(); TransAssert(RetE && "Bad Return Value!"); llvm::DenseMap ParmRefToStrMap; llvm::DenseMap::iterator I = ReturnStmtToParmRefs.find(TheReturnStmt); if (I != ReturnStmtToParmRefs.end()) { ParmRefsVector *PVector = (*I).second; TransAssert(PVector); for (ParmRefsVector::const_iterator I = PVector->begin(), E = PVector->end(); I != E; ++I) { std::string ParmRefStr(""); getNewParmRefStr((*I), ParmRefStr); ParmRefToStrMap[(*I)] = ParmRefStr; } } std::string RetString; RewriteHelper->getExprString(RetE, RetString); replaceParmRefs(RetString, RetE, ParmRefToStrMap); std::string ParenRetString = "(" + RetString + ")"; RewriteHelper->replaceExpr(TheCallExpr, ParenRetString); } ReplaceCallExpr::~ReplaceCallExpr(void) { delete CollectionVisitor; for (llvm::DenseMap::iterator I = FuncToReturnStmts.begin(), E = FuncToReturnStmts.end(); I != E; ++I) { delete (*I).second; } for (llvm::DenseMap::iterator I = ReturnStmtToParmRefs.begin(), E = ReturnStmtToParmRefs.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/ReplaceCallExpr.h000066400000000000000000000060671402162750500202540ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_CALL_EXPR_H #define REPLACE_CALL_EXPR_H #include #include #include #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class CallExpr; class DeclRefExpr; class ReturnStmt; class Expr; class ParmVarDecl; } class ReplaceCallExprVisitor; class ReplaceCallExpr : public Transformation { friend class ReplaceCallExprVisitor; public: ReplaceCallExpr(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheCallExpr(NULL), TheReturnStmt(NULL), CurrentFD(NULL) { } ~ReplaceCallExpr(void); private: typedef llvm::SmallVector ReturnStmtsVector; typedef llvm::SmallVector ParmRefsVector; typedef llvm::SmallVector ParameterPosVector; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addOneReturnStmt(clang::ReturnStmt *RS); void addOneParmRef(clang::ReturnStmt *RS, const clang::DeclRefExpr *DE); void replaceCallExpr(void); void getNewParmRefStr(const clang::DeclRefExpr *DE, std::string &ParmRefStr); void replaceParmRefs(std::string &RetStr, const clang::Expr *RetE, llvm::DenseMap &ParmRefToStrMap); void insertParmRef( std::vector< std::pair > &SortedParmRefs, const clang::DeclRefExpr *ParmRef, int Off); void sortParmRefsByOffs(const char *StartBuf, llvm::DenseMap &ParmRefToStrMap, std::vector > &SortedParmRefs); void doAnalysis(void); void getParmPosVector(ParameterPosVector &PosVector, clang::ReturnStmt *RS, clang::CallExpr *CE); bool hasBadEffect(const ParameterPosVector &PosVector, clang::ReturnStmt *RS, clang::CallExpr *CE); bool hasUnmatchedParmArg(const ParameterPosVector &PosVector, clang::CallExpr *CE); ReplaceCallExprVisitor *CollectionVisitor; llvm::DenseMap FuncToReturnStmts; llvm::DenseMap ReturnStmtToParmRefs; llvm::SmallVector AllCallExprs; clang::CallExpr *TheCallExpr; clang::ReturnStmt *TheReturnStmt; clang::FunctionDecl *CurrentFD; // Unimplemented ReplaceCallExpr(void); ReplaceCallExpr(const ReplaceCallExpr &); void operator=(const ReplaceCallExpr &); }; #endif cvise-2.3.0/clang_delta/ReplaceClassWithBaseTemplateSpec.cpp000066400000000000000000000121561402162750500240740ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceClassWithBaseTemplateSpec.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass tries to replace a class with its base class if \n\ * this class has only one base class, and \n\ * this class doesn't have any explicit declaration, and \n\ * the base class is a class template specialization \n\ "; static RegisterTransformation Trans("replace-class-with-base-template-spec", DescriptionMsg); class ReplaceClassWithBaseTemplateSpecVisitor : public RecursiveASTVisitor { public: explicit ReplaceClassWithBaseTemplateSpecVisitor( ReplaceClassWithBaseTemplateSpec *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: ReplaceClassWithBaseTemplateSpec *ConsumerInstance; }; bool ReplaceClassWithBaseTemplateSpecVisitor::VisitCXXRecordDecl( CXXRecordDecl *CXXRD) { if (ConsumerInstance->isInIncludedFile(CXXRD) || ConsumerInstance->isSpecialRecordDecl(CXXRD) || !CXXRD->hasDefinition()) return true; ConsumerInstance->handleOneCXXRecordDecl(CXXRD->getDefinition()); return true; } class ReplaceClassWithBaseTemplateSpecRewriteVisitor : public RecursiveASTVisitor { public: explicit ReplaceClassWithBaseTemplateSpecRewriteVisitor( ReplaceClassWithBaseTemplateSpec *Instance) : ConsumerInstance(Instance) { } bool VisitRecordTypeLoc(RecordTypeLoc TLoc); private: ReplaceClassWithBaseTemplateSpec *ConsumerInstance; }; bool ReplaceClassWithBaseTemplateSpecRewriteVisitor::VisitRecordTypeLoc( RecordTypeLoc TLoc) { const Type *Ty = TLoc.getTypePtr(); if (Ty->isUnionType()) return true; const CXXRecordDecl *RD = dyn_cast(TLoc.getDecl()); if (!RD || (RD->getCanonicalDecl() != ConsumerInstance->TheCXXRecord)) return true; ConsumerInstance->RewriteHelper->replaceRecordType( TLoc, ConsumerInstance->TheBaseName + " "); return true; } void ReplaceClassWithBaseTemplateSpec::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceClassWithBaseTemplateSpecVisitor(this); RewriteVisitor = new ReplaceClassWithBaseTemplateSpecRewriteVisitor(this); } void ReplaceClassWithBaseTemplateSpec::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheCXXRecord && "TheCXXRecord is NULL!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); removeBaseSpecifier(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceClassWithBaseTemplateSpec::handleOneCXXRecordDecl( const CXXRecordDecl *CXXRD) { TransAssert(CXXRD && "NULL CXXRD!"); TransAssert(CXXRD->isThisDeclarationADefinition() && "Not a definition!"); if (getNumExplicitDecls(CXXRD)) return; if (CXXRD->getNumBases() != 1) return; CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(); const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); if (!Base || !Base->hasDefinition() || !Base->getDescribedClassTemplate()) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { BS->getType().getAsStringInternal(TheBaseName, Context->getPrintingPolicy()); TheCXXRecord = CXXRD; } } void ReplaceClassWithBaseTemplateSpec::removeBaseSpecifier(void) { unsigned NumBases = TheCXXRecord->getNumBases(); (void)NumBases; TransAssert((NumBases == 1) && "TheCXXRecord can have only one base!"); SourceLocation StartLoc = TheCXXRecord->getLocation(); StartLoc = RewriteHelper->getLocationUntil(StartLoc, ':'); SourceLocation EndLoc = RewriteHelper->getLocationUntil(StartLoc, '{'); EndLoc = EndLoc.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); } ReplaceClassWithBaseTemplateSpec::~ReplaceClassWithBaseTemplateSpec(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ReplaceClassWithBaseTemplateSpec.h000066400000000000000000000033541402162750500235410ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_CLASS_WITH_BASE_TEMPLATE_SPEC_H #define REPLACE_CLASS_WITH_BASE_TEMPLATE_SPEC_H #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; } class ReplaceClassWithBaseTemplateSpecVisitor; class ReplaceClassWithBaseTemplateSpecRewriteVisitor; class ReplaceClassWithBaseTemplateSpec : public Transformation { friend class ReplaceClassWithBaseTemplateSpecVisitor; friend class ReplaceClassWithBaseTemplateSpecRewriteVisitor; public: ReplaceClassWithBaseTemplateSpec(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheCXXRecord(NULL), TheBaseName("") { } ~ReplaceClassWithBaseTemplateSpec(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneCXXRecordDecl(const clang::CXXRecordDecl *CXXRD); void removeBaseSpecifier(void); ReplaceClassWithBaseTemplateSpecVisitor *CollectionVisitor; ReplaceClassWithBaseTemplateSpecRewriteVisitor *RewriteVisitor; const clang::CXXRecordDecl *TheCXXRecord; std::string TheBaseName; // Unimplemented ReplaceClassWithBaseTemplateSpec(void); ReplaceClassWithBaseTemplateSpec(const ReplaceClassWithBaseTemplateSpec &); void operator=(const ReplaceClassWithBaseTemplateSpec &); }; #endif cvise-2.3.0/clang_delta/ReplaceDependentName.cpp000066400000000000000000000117021402162750500215740ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceDependentName.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass replaces a dependent name (referred by typename) with \n\ a resolved type by looking up this dependent name in its decl context. \n\ "; static RegisterTransformation Trans("replace-dependent-name", DescriptionMsg); class ReplaceDependentNameCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceDependentNameCollectionVisitor(ReplaceDependentName *Instance) : ConsumerInstance(Instance) { } bool VisitDependentNameTypeLoc(DependentNameTypeLoc TLoc); bool VisitElaboratedTypeLoc(ElaboratedTypeLoc TLoc); private: ReplaceDependentName *ConsumerInstance; }; bool ReplaceDependentNameCollectionVisitor::VisitDependentNameTypeLoc( DependentNameTypeLoc TLoc) { ConsumerInstance->handleOneDependentNameTypeLoc(TLoc); return true; } bool ReplaceDependentNameCollectionVisitor::VisitElaboratedTypeLoc( ElaboratedTypeLoc TLoc) { ConsumerInstance->handleOneElaboratedTypeLoc(TLoc); return true; } void ReplaceDependentName::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceDependentNameCollectionVisitor(this); } void ReplaceDependentName::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); rewriteDependentName(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } SourceLocation ReplaceDependentName::getElaboratedTypeLocBegin( const ElaboratedTypeLoc &TLoc) { SourceLocation Loc = TLoc.getElaboratedKeywordLoc(); if (Loc.isValid()) return Loc; NestedNameSpecifierLoc SpecLoc = TLoc.getQualifierLoc(); NestedNameSpecifierLoc Prefix = SpecLoc.getPrefix(); while (Prefix.getBeginLoc().isValid()) { SpecLoc = Prefix; Prefix = Prefix.getPrefix(); } Loc = SpecLoc.getBeginLoc(); TransAssert(Loc.isValid() && "Failed to get ElaboratedTypeLoc!"); return Loc; } void ReplaceDependentName::handleOneElaboratedTypeLoc( const ElaboratedTypeLoc &TLoc) { SourceLocation Loc = TLoc.getBeginLoc(); if (Loc.isInvalid() || isInIncludedFile(Loc)) return; const ElaboratedType *ET = TLoc.getTypePtr(); if ((ET->getKeyword() != ETK_Typename) && (ET->getKeyword() != ETK_None)) return; if (TLoc.getQualifierLoc().getBeginLoc().isInvalid()) return; std::string Str = ""; if (ValidInstanceNum == 8) TransAssert(ET); bool Typename = false; if (!getTypeString(ET->getNamedType(), Str, Typename)) return; std::string TyStr = ""; ET->getNamedType().getAsStringInternal(TyStr, Context->getPrintingPolicy()); if (TyStr == Str) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheTyName = Str; NeedTypenameKeyword = Typename; TheLocBegin = getElaboratedTypeLocBegin(TLoc); TheNameLocEnd = TLoc.getEndLoc(); } } void ReplaceDependentName::handleOneDependentNameTypeLoc( const DependentNameTypeLoc &TLoc) { SourceLocation Loc = TLoc.getBeginLoc(); if (Loc.isInvalid() || isInIncludedFile(Loc)) return; const DependentNameType *DNT = dyn_cast(TLoc.getTypePtr()); TransAssert(DNT && "NULL DependentNameType!"); if (DNT->getKeyword() != ETK_Typename) return; std::string Str = ""; bool Typename = false; if (!getDependentNameTypeString(DNT, Str, Typename)) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheTyName = Str; NeedTypenameKeyword = Typename; TheLocBegin = TLoc.getElaboratedKeywordLoc(); TheNameLocEnd = TLoc.getEndLoc(); } } void ReplaceDependentName::rewriteDependentName() { std::string NewStr = ""; if (NeedTypenameKeyword) NewStr += "typename "; NewStr += TheTyName; TheRewriter.ReplaceText(SourceRange(TheLocBegin, TheNameLocEnd), NewStr); } ReplaceDependentName::~ReplaceDependentName() { delete CollectionVisitor; } cvise-2.3.0/clang_delta/ReplaceDependentName.h000066400000000000000000000033741402162750500212470ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_DEPENDENT_NAME_H #define REPLACE_DEPENDENT_NAME_H #include #include "clang/Basic/SourceLocation.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class DependentNameTypeLoc; class ElaboratedTypeLoc; } class ReplaceDependentNameCollectionVisitor; class ReplaceDependentName : public Transformation { friend class ReplaceDependentNameCollectionVisitor; public: ReplaceDependentName(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheTyName(""), NeedTypenameKeyword(false) {} ~ReplaceDependentName(); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneDependentNameTypeLoc(const clang::DependentNameTypeLoc &TLoc); void handleOneElaboratedTypeLoc(const clang::ElaboratedTypeLoc &TLoc); void rewriteDependentName(); clang::SourceLocation getElaboratedTypeLocBegin( const clang::ElaboratedTypeLoc &TLoc); ReplaceDependentNameCollectionVisitor *CollectionVisitor; std::string TheTyName; bool NeedTypenameKeyword; clang::SourceLocation TheLocBegin; clang::SourceLocation TheNameLocEnd; // Unimplemented ReplaceDependentName(); ReplaceDependentName(const ReplaceDependentName &); void operator=(const ReplaceDependentName &); }; #endif cvise-2.3.0/clang_delta/ReplaceDependentTypedef.cpp000066400000000000000000000102771402162750500223220ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceDependentTypedef.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass replaces typedef names with the underlying type if the \ underlying type is dependent, e.g.: \n\ \n\ template struct S { typedef T type; }; \n\ struct A { }; \n\ struct B { typedef S::type type; }; \n\ ==> \n\ template struct S { typedef T type; }; \n\ struct A { }; \n\ struct B { typedef A type; }; \n\ \n\ It also tries to reduce the typedef chain, e.g. \n\ typedef long xx_t; \n\ typedef xx_t xx; \n\ ==> \n\ typedef long xx_t; \n\ typedef long xx; \n\ "; static RegisterTransformation Trans("replace-dependent-typedef", DescriptionMsg); class ReplaceDependentTypedefCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceDependentTypedefCollectionVisitor(ReplaceDependentTypedef *Instance) : ConsumerInstance(Instance) { } bool VisitTypedefDecl(TypedefDecl *D); private: ReplaceDependentTypedef *ConsumerInstance; }; bool ReplaceDependentTypedefCollectionVisitor::VisitTypedefDecl(TypedefDecl *D) { ConsumerInstance->handleOneTypedefDecl(D); return true; } void ReplaceDependentTypedef::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceDependentTypedefCollectionVisitor(this); } void ReplaceDependentTypedef::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); rewriteTypedefDecl(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool ReplaceDependentTypedef::isValidType(const QualType &QT) { const Type *Ty = QT.getTypePtr(); Type::TypeClass TC = Ty->getTypeClass(); switch (TC) { case Type::SubstTemplateTypeParm: case Type::Typedef: case Type::DependentName: // fall-through return true; case Type::Elaborated: { const ElaboratedType *ETy = dyn_cast(Ty); ElaboratedTypeKeyword Keyword = ETy->getKeyword(); return ((Keyword == ETK_Typename) || (Keyword == ETK_None)); } default: return false; } TransAssert(0 && "Unreachable code!"); return false; } void ReplaceDependentTypedef::handleOneTypedefDecl(const TypedefDecl *D) { if (isInIncludedFile(D) || D->getBeginLoc().isInvalid()) return; if (!isValidType(D->getUnderlyingType())) return; std::string Str = ""; bool Typename = false; if (!getTypeString(D->getUnderlyingType(), Str, Typename)) return; std::string TdefTyStr = ""; D->getUnderlyingType().getAsStringInternal( TdefTyStr, Context->getPrintingPolicy()); if (Str == TdefTyStr) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheTypedefDecl = D; TheTyName = Str; NeedTypenameKeyword = Typename; } } void ReplaceDependentTypedef::rewriteTypedefDecl() { std::string NewStr = "typedef "; if (NeedTypenameKeyword) NewStr += "typename "; NewStr = NewStr + TheTyName + " " + TheTypedefDecl->getNameAsString(); SourceRange Range = TheTypedefDecl->getSourceRange(); TheRewriter.ReplaceText(Range, NewStr); } ReplaceDependentTypedef::~ReplaceDependentTypedef() { delete CollectionVisitor; } cvise-2.3.0/clang_delta/ReplaceDependentTypedef.h000066400000000000000000000032351402162750500217630ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_DEPENDENT_TYPEDEF_H #define REPLACE_DEPENDENT_TYPEDEF_H #include #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class QualType; class Type; class TypedefDecl; class CXXRecordDecl; } namespace llvm { class StringRef; } class ReplaceDependentTypedefCollectionVisitor; class ReplaceDependentTypedef : public Transformation { friend class ReplaceDependentTypedefCollectionVisitor; public: ReplaceDependentTypedef(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheTyName(""), TheTypedefDecl(NULL), NeedTypenameKeyword(false) {} ~ReplaceDependentTypedef(); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneTypedefDecl(const clang::TypedefDecl *D); bool isValidType(const clang::QualType &QT); void rewriteTypedefDecl(); ReplaceDependentTypedefCollectionVisitor *CollectionVisitor; std::string TheTyName; const clang::TypedefDecl *TheTypedefDecl; bool NeedTypenameKeyword; // Unimplemented ReplaceDependentTypedef(); ReplaceDependentTypedef(const ReplaceDependentTypedef &); void operator=(const ReplaceDependentTypedef &); }; #endif cvise-2.3.0/clang_delta/ReplaceDerivedClass.cpp000066400000000000000000000133751402162750500214450ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2018 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceDerivedClass.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "CommonRenameClassRewriteVisitor.h" #include "TransformationManager.h" using namespace clang; using namespace clang_delta_common_visitor; static const char *DescriptionMsg = "Replace a derived class with one of its base classes if \n\ * the derived class is empty; \n\ * and if the base class and the derived class are both class templates, \ they require the same number of arguments for instantiation. \n"; static RegisterTransformation Trans("replace-derived-class", DescriptionMsg); class ReplaceDerivedClassASTVisitor : public RecursiveASTVisitor { public: explicit ReplaceDerivedClassASTVisitor(ReplaceDerivedClass *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: ReplaceDerivedClass *ConsumerInstance; }; class ReplaceDerivedClassRewriteVisitor : public CommonRenameClassRewriteVisitor { public: ReplaceDerivedClassRewriteVisitor(Transformation *Instance, Rewriter *RT, RewriteUtils *Helper, const CXXRecordDecl *CXXRD, const std::string &Name) : CommonRenameClassRewriteVisitor (Instance, RT, Helper, CXXRD, Name) { } }; bool ReplaceDerivedClassASTVisitor::VisitCXXRecordDecl(CXXRecordDecl *CXXRD) { ConsumerInstance->handleOneCXXRecordDecl(CXXRD); return true; } void ReplaceDerivedClass::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceDerivedClassASTVisitor(this); } void ReplaceDerivedClass::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheDerivedClass && "TheDerivedClass is NULL!"); TransAssert(TheBaseClass && "TheBaseClass is NULL!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); RewriteVisitor = new ReplaceDerivedClassRewriteVisitor(this, &TheRewriter, RewriteHelper, TheDerivedClass->getCanonicalDecl(), TheBaseClass->getNameAsString()); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doRewrite(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool ReplaceDerivedClass::isValidBaseDerivedPair(const CXXRecordDecl *Base, const CXXRecordDecl *Derived) { const ClassTemplateDecl *BaseTmplD = Base->getDescribedClassTemplate(); const ClassTemplateDecl *DerivedTmplD = Derived->getDescribedClassTemplate(); if (!BaseTmplD && !DerivedTmplD) { return true; } else if (BaseTmplD && DerivedTmplD) { return (BaseTmplD->getTemplateParameters()->getMinRequiredArguments() == DerivedTmplD->getTemplateParameters()->getMinRequiredArguments()); } return false; } bool ReplaceDerivedClass::isEmptyClass(const CXXRecordDecl *CXXDef) { TransAssert(CXXDef->isThisDeclarationADefinition() && "CXXDef must be a definition!"); const DeclContext *Ctx = dyn_cast(CXXDef); TransAssert(Ctx && "Invalid DeclContext!"); for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if (!(*I)->isImplicit()) return false; } return true; } void ReplaceDerivedClass::handleOneCXXRecordDecl(const CXXRecordDecl *CXXRD) { if (isInIncludedFile(CXXRD)) return; const CXXRecordDecl *CXXDef = CXXRD->getDefinition(); if (!CXXDef) return; if (dyn_cast(CXXRD)) return; if ((CXXDef->getNumBases() == 0) || !isEmptyClass(CXXDef)) return; const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl(); if (VisitedCXXRecordDecls.count(CanonicalRD)) return; VisitedCXXRecordDecls.insert(CanonicalRD); for (CXXRecordDecl::base_class_const_iterator I = CanonicalRD->bases_begin(), E = CanonicalRD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); if (!Base || !isValidBaseDerivedPair(Base, CanonicalRD)) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheBaseClass = Base; TheDerivedClass = CanonicalRD; } } } void ReplaceDerivedClass::doRewrite(void) { if (const ClassTemplateDecl *TmplD = TheDerivedClass->getDescribedClassTemplate()) { RewriteHelper->removeClassTemplateDecls(TmplD); } else { if (!isDeclaringRecordDecl(TheDerivedClass)) { RewriteHelper->removeClassDecls(TheDerivedClass); } } } ReplaceDerivedClass::~ReplaceDerivedClass(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ReplaceDerivedClass.h000066400000000000000000000036461402162750500211120ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_DERIVED_CLASS_H #define REPLACE_DERIVED_CLASS_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXRecordDecl; } class ReplaceDerivedClassASTVisitor; class ReplaceDerivedClassRewriteVisitor; class ReplaceDerivedClass : public Transformation { friend class ReplaceDerivedClassASTVisitor; friend class ReplaceDerivedClassRewriteVisitor; public: ReplaceDerivedClass(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheDerivedClass(NULL), TheBaseClass(NULL) { } ~ReplaceDerivedClass(void); private: typedef llvm::SmallPtrSet CXXRecordDeclSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); bool isValidBaseDerivedPair(const clang::CXXRecordDecl *Base, const clang::CXXRecordDecl *Derived); bool isEmptyClass(const clang::CXXRecordDecl *CXXDef); void handleOneCXXRecordDecl(const clang::CXXRecordDecl *CXXRD); void doRewrite(void); CXXRecordDeclSet VisitedCXXRecordDecls; ReplaceDerivedClassASTVisitor *CollectionVisitor; ReplaceDerivedClassRewriteVisitor *RewriteVisitor; const clang::CXXRecordDecl *TheDerivedClass; const clang::CXXRecordDecl *TheBaseClass; // Unimplemented ReplaceDerivedClass(void); ReplaceDerivedClass(const ReplaceDerivedClass &); void operator=(const ReplaceDerivedClass &); }; #endif cvise-2.3.0/clang_delta/ReplaceFunctionDefWithDecl.cpp000066400000000000000000000253761402162750500227310ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceFunctionDefWithDecl.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass replaces a function's definition with its declaration.\n"; static RegisterTransformation Trans("replace-function-def-with-decl", DescriptionMsg); class ReplaceFunctionDefWithDeclCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceFunctionDefWithDeclCollectionVisitor( ReplaceFunctionDefWithDecl *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ReplaceFunctionDefWithDecl *ConsumerInstance; }; bool ReplaceFunctionDefWithDeclCollectionVisitor::VisitFunctionDecl( FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD)) return true; if (FD->isThisDeclarationADefinition() && FD->hasBody() && !FD->isDeleted() && !FD->isDefaulted()) { ConsumerInstance->addOneFunctionDef(FD); } return true; } void ReplaceFunctionDefWithDecl::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceFunctionDefWithDeclCollectionVisitor(this); } void ReplaceFunctionDefWithDecl::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (!checkCounterValidity()) return; Ctx.getDiagnostics().setSuppressAllDiagnostics(false); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } unsigned ReplaceFunctionDefWithDecl::getNumWrittenInitializers( const CXXConstructorDecl *Ctor) { unsigned Num = 0; for (CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(), E = Ctor->init_end(); I != E; ++I) { const CXXCtorInitializer *Init = (*I); if (Init->isWritten()) Num++; } return Num; } void ReplaceFunctionDefWithDecl::removeCtorInitializers( const CXXConstructorDecl *Ctor) { if (!getNumWrittenInitializers(Ctor)) return; CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(); while (!(*I)->isWritten()) ++I; const CXXCtorInitializer *FirstInit = (*I); SourceRange Range = FirstInit->getSourceRange(); SourceLocation LocStart = Range.getBegin(); // RewriteHelper->removeTextFromLeftAt(Range, ':', // LocStart.getLocWithOffset(-1)); // make sure we handle cases like: // namespace NS { struct A {}; } // struct B : NS::A { B() : NS::A() {} }; SourceLocation Loc = RewriteHelper->getLocationFromLeftUntil(LocStart, ':'); Loc = RewriteHelper->getLocationFromLeftUntil(Loc, ')'); TheRewriter.RemoveText(SourceRange(Loc.getLocWithOffset(1), LocStart.getLocWithOffset(-1))); CXXConstructorDecl::init_const_iterator E = Ctor->init_end(); --E; while (!(*E)->isWritten()) --E; const CXXCtorInitializer *LastInit = (*E); TransAssert(LastInit->isWritten() && "Init is not written!"); SourceLocation LocEnd = LastInit->getSourceRange().getEnd(); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); } bool ReplaceFunctionDefWithDecl::hasValidOuterLocStart( const FunctionTemplateDecl *FTD, const FunctionDecl *FD) { SourceLocation FTDLocStart = FTD->getSourceRange().getBegin(); SourceLocation FDLocStart = FD->getSourceRange().getBegin(); const char *FTDStartPos = SrcManager->getCharacterData(FTDLocStart); const char *FDStartPos = SrcManager->getCharacterData(FDLocStart); return (FDStartPos < FTDStartPos); } bool ReplaceFunctionDefWithDecl::removeOneInlineKeyword( const std::string &LeadingInlineStr, const std::string &InlineStr, const std::string &Str, const SourceLocation &StartLoc) { if (!Str.compare(0, LeadingInlineStr.length(), LeadingInlineStr)) { TheRewriter.RemoveText(SourceRange( StartLoc, StartLoc.getLocWithOffset(LeadingInlineStr.length() - 1))); return true; } size_t Off = Str.find(InlineStr); if (Off == std::string::npos) return false; TheRewriter.RemoveText(SourceRange( StartLoc.getLocWithOffset(Off), StartLoc.getLocWithOffset(Off + InlineStr.length() - 1))); return true; } bool ReplaceFunctionDefWithDecl::removeInlineKeyword( const std::string &InlineStr, const std::string &Str, const SourceLocation &StartLoc) { char Spaces[] = {' ', '\t', '\r', '\n'}; unsigned Len = sizeof(Spaces) / sizeof(char); for (unsigned I = 0; I < Len; ++I) { std::string LeadingInlineStr = InlineStr + Spaces[I]; for (unsigned J = 0; J < Len; ++J) { for (unsigned K = 0; K < Len; ++K) { std::string InlineStrVariant = Spaces[J] + InlineStr + Spaces[K]; if (removeOneInlineKeyword(LeadingInlineStr, InlineStrVariant, Str, StartLoc)) return true; } } } return false; } void ReplaceFunctionDefWithDecl::removeStringBeforeTypeIdentifier( const SourceLocation &StartLoc, const SourceLocation &EndLoc) { const char *StartPos = SrcManager->getCharacterData(StartLoc); const char *EndPos = SrcManager->getCharacterData(EndLoc); // skip the first char of function's name EndPos--; while (isspace(*EndPos) && (EndPos != StartPos)) { EndPos--; } assert((EndPos > StartPos) && "Invalid EndPos!"); while (!isspace(*EndPos) && (EndPos != StartPos)) { EndPos--; } EndPos++; assert((EndPos != StartPos) && "Bad Type Location?"); TheRewriter.RemoveText(StartLoc, EndPos - StartPos); } void ReplaceFunctionDefWithDecl::removeInlineKeywordFromOneFunctionDecl( const FunctionDecl *FD) { if (!FD->isInlineSpecified()) return; SourceLocation StartLoc = FD->getSourceRange().getBegin(); SourceLocation EndLoc = FD->getLocation(); std::string Str; RewriteHelper->getStringBetweenLocs(Str, StartLoc, EndLoc); if (removeInlineKeyword("inline", Str, StartLoc)) return; if (removeInlineKeyword("_inline", Str, StartLoc)) return; if (removeInlineKeyword("__inline", Str, StartLoc)) return; if (removeInlineKeyword("__forceinline", Str, StartLoc)) return; if (removeInlineKeyword("__inline__", Str, StartLoc)) return; // OK, just remove whatever appears before the type identifier... // It's mainly for dealing with non-preprocessed code removeStringBeforeTypeIdentifier(StartLoc, EndLoc); } void ReplaceFunctionDefWithDecl::removeInlineKeywordFromFunctionDecls( const FunctionDecl *FD) { if (!FD->isInlineSpecified()) return; const FunctionDecl *FirstFD = FD->getCanonicalDecl(); for (FunctionDecl::redecl_iterator I = FirstFD->redecls_begin(), E = FirstFD->redecls_end(); I != E; ++I) { removeInlineKeywordFromOneFunctionDecl(*I); } } void ReplaceFunctionDefWithDecl::rewriteOneFunctionDef( const FunctionDecl *FD) { const CXXMethodDecl *CXXMD = dyn_cast(FD); if (!CXXMD) { RewriteHelper->replaceFunctionDefWithStr(FD, ";"); // compiler warns about used-but-not-defined inlined specified function, // so get rid of the inline keyword from FD's decls removeInlineKeywordFromFunctionDecls(FD); return; } if (CXXMD->isOutOfLine()) { // Not sure why, but FD->getOuterLocStart() doesn't work well for // function template decl, e.g. for the code below: // struct A { template A(); }; // template A::A() {} // FD->getOuterLocStart() returns the same LocStart as // FD->getSourceRange().getBegin(), so we have to check if FD has // described function template if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) { // here is another ugly part, without this check, we couldn't remove // "template in the following code: // template struct S {template void foo();}; // template template void S::foo() { } if (!hasValidOuterLocStart(FTD, FD)) { TheRewriter.RemoveText(FTD->getSourceRange()); return; } } SourceRange R = FD->getSourceRange(); SourceLocation LocStart = R.getBegin(); SourceLocation LocEnd = R.getEnd(); if (LocStart.isMacroID()) { LocStart = SrcManager->getFileLoc(LocStart); } TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); return; } if (const CXXConstructorDecl *Ctor = dyn_cast(FD)) { removeCtorInitializers(Ctor); } RewriteHelper->replaceFunctionDefWithStr(FD, ";"); removeInlineKeywordFromFunctionDecls(FD); } void ReplaceFunctionDefWithDecl::doRewriting() { if (ToCounter <= 0) { TransAssert(TheFunctionDef && "NULL TheFunctionDef!"); rewriteOneFunctionDef(TheFunctionDef); return; } TransAssert((TransformationCounter <= static_cast(AllValidFunctionDefs.size())) && "TransformationCounter is larger than the number of defs!"); TransAssert((ToCounter <= static_cast(AllValidFunctionDefs.size())) && "ToCounter is larger than the number of defs!"); // To cope with local struct definition defined inside a function // to be replaced, e.g.: // void foo(void) { { struct A { A() {} }; } } // If we replace foo() {...} first, we will mess up when we try to // replace A() {} because its text has gone already for (int I = ToCounter; I >= TransformationCounter; --I) { TransAssert((I >= 1) && "Invalid Index!"); const FunctionDecl *FD = AllValidFunctionDefs[I-1]; TransAssert(FD && "NULL FunctionDecl!"); rewriteOneFunctionDef(FD); } } void ReplaceFunctionDefWithDecl::addOneFunctionDef(const FunctionDecl *FD) { // If DoPreserveRoutine is set, and our current routine is the one we're // preserving, then skip it if (DoPreserveRoutine && FD->getQualifiedNameAsString() == PreserveRoutine) return; ValidInstanceNum++; if (ToCounter > 0) { AllValidFunctionDefs.push_back(FD); return; } if (ValidInstanceNum == TransformationCounter) TheFunctionDef = FD; } ReplaceFunctionDefWithDecl::~ReplaceFunctionDefWithDecl() { delete CollectionVisitor; } cvise-2.3.0/clang_delta/ReplaceFunctionDefWithDecl.h000066400000000000000000000055331402162750500223670ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_FUNCTION_DEF_WITH_DECL_H #define REPLACE_FUNCTION_DEF_WITH_DECL_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class CXXConstructorDecl; class FunctionTemplateDecl; class SourceLocation; } class ReplaceFunctionDefWithDeclCollectionVisitor; class ReplaceFunctionDefWithDecl : public Transformation { friend class ReplaceFunctionDefWithDeclCollectionVisitor; public: // enable rewriting multiple instances ReplaceFunctionDefWithDecl(const char *TransName, const char *Desc) : Transformation(TransName, Desc, /*MultipleRewrites=*/true), CollectionVisitor(NULL), TheFunctionDef(NULL) { } ~ReplaceFunctionDefWithDecl(); private: typedef llvm::SmallVector FunctionDeclVector; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addOneFunctionDef(const clang::FunctionDecl *FD); void rewriteOneFunctionDef(const clang::FunctionDecl *FD); void removeCtorInitializers(const clang::CXXConstructorDecl *Ctor); unsigned getNumWrittenInitializers(const clang::CXXConstructorDecl *Ctor); bool hasValidOuterLocStart(const clang::FunctionTemplateDecl *FTD, const clang::FunctionDecl *FD); void removeStringBeforeTypeIdentifier(const clang::SourceLocation &StartLoc, const clang::SourceLocation &EndLoc); bool removeOneInlineKeyword(const std::string &LeadingInlineStr, const std::string &InlineStr, const std::string &Str, const clang::SourceLocation &StartLoc); bool removeInlineKeyword(const std::string &InlineStr, const std::string &Str, const clang::SourceLocation &StartLoc); void removeInlineKeywordFromOneFunctionDecl(const clang::FunctionDecl *FD); void removeInlineKeywordFromFunctionDecls(const clang::FunctionDecl *FD); void doRewriting(); FunctionDeclVector AllValidFunctionDefs; ReplaceFunctionDefWithDeclCollectionVisitor *CollectionVisitor; const clang::FunctionDecl *TheFunctionDef; // Unimplemented ReplaceFunctionDefWithDecl(void); ReplaceFunctionDefWithDecl(const ReplaceFunctionDefWithDecl &); void operator=(const ReplaceFunctionDefWithDecl &); }; #endif cvise-2.3.0/clang_delta/ReplaceOneLevelTypedefType.cpp000066400000000000000000000103001402162750500227520ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceOneLevelTypedefType.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass literally replaces a typedef type with the underlying type \ if typedef type is only been used once. It doesn't recursively resolve \ the underlying type."; static RegisterTransformation Trans("replace-one-level-typedef-type", DescriptionMsg); class ReplaceOneLevelTypedefTypeCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceOneLevelTypedefTypeCollectionVisitor( ReplaceOneLevelTypedefType *Instance) : ConsumerInstance(Instance) { } bool VisitTypedefTypeLoc(TypedefTypeLoc TLoc); private: ReplaceOneLevelTypedefType *ConsumerInstance; }; bool ReplaceOneLevelTypedefTypeCollectionVisitor::VisitTypedefTypeLoc( TypedefTypeLoc TLoc) { ConsumerInstance->handleOneTypedefTypeLoc(TLoc); return true; } void ReplaceOneLevelTypedefType::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceOneLevelTypedefTypeCollectionVisitor(this); } void ReplaceOneLevelTypedefType::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); analyzeTypeLocs(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheTypedefDecl && "NULL TheTypedefDecl!"); rewriteTypedefType(); removeTypedefs(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceOneLevelTypedefType::analyzeTypeLocs() { for (TypedefDeclToRefMap::iterator I = AllTypeDecls.begin(), E = AllTypeDecls.end(); I != E; ++I) { TypedefTypeLocVector *LocVec = (*I).second; if (LocVec->size() > 1) continue; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheTypedefDecl = (*I).first; TheTypeLoc = LocVec->back(); } } } void ReplaceOneLevelTypedefType::rewriteTypedefType() { std::string NewTyStr; TheTypedefDecl->getUnderlyingType().getAsStringInternal(NewTyStr, Context->getPrintingPolicy()); SourceRange Range = TheTypeLoc.getSourceRange(); TheRewriter.ReplaceText(Range, NewTyStr); } void ReplaceOneLevelTypedefType::removeTypedefs() { for (TypedefDecl::redecl_iterator I = TheTypedefDecl->redecls_begin(), E = TheTypedefDecl->redecls_end(); I != E; ++I) { SourceRange Range = (*I)->getSourceRange(); if (Range.isValid()) { RewriteHelper->removeTextUntil(Range, ';'); Rewritten = true; } } } void ReplaceOneLevelTypedefType::handleOneTypedefTypeLoc(TypedefTypeLoc TLoc) { if (isInIncludedFile(TLoc.getBeginLoc())) return; const TypedefType *TdefTy = TLoc.getTypePtr(); const TypedefDecl *TdefD = dyn_cast(TdefTy->getDecl()); if (!TdefD || TdefD->getBeginLoc().isInvalid()) return; const TypedefDecl *CanonicalD = dyn_cast(TdefD->getCanonicalDecl()); TypedefTypeLocVector *LocVec = AllTypeDecls[CanonicalD]; if (!LocVec) { LocVec = new TypedefTypeLocVector(); TransAssert(LocVec && "NULL LocVec!"); AllTypeDecls[CanonicalD] = LocVec; } LocVec->push_back(TLoc); } ReplaceOneLevelTypedefType::~ReplaceOneLevelTypedefType(void) { for (TypedefDeclToRefMap::iterator I = AllTypeDecls.begin(), E = AllTypeDecls.end(); I != E; ++I) { delete (*I).second; } delete CollectionVisitor; } cvise-2.3.0/clang_delta/ReplaceOneLevelTypedefType.h000066400000000000000000000035371402162750500224350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_ONE_LEVEL_TYPEDEF_TYPE_H #define REPLACE_ONE_LEVEL_TYPEDEF_TYPE_H #include "Transformation.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "clang/AST/TypeLoc.h" namespace clang { class DeclGroupRef; class ASTContext; class TypedefDecl; } class ReplaceOneLevelTypedefTypeCollectionVisitor; class ReplaceOneLevelTypedefType : public Transformation { friend class ReplaceOneLevelTypedefTypeCollectionVisitor; public: ReplaceOneLevelTypedefType(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL) {} ~ReplaceOneLevelTypedefType(void); private: typedef llvm::SmallVector TypedefTypeLocVector; typedef llvm::MapVector TypedefDeclToRefMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneTypedefTypeLoc(clang::TypedefTypeLoc TLoc); void analyzeTypeLocs(); void rewriteTypedefType(); void removeTypedefs(); TypedefDeclToRefMap AllTypeDecls; clang::TypedefTypeLoc TheTypeLoc; ReplaceOneLevelTypedefTypeCollectionVisitor *CollectionVisitor; const clang::TypedefDecl *TheTypedefDecl; // Unimplemented ReplaceOneLevelTypedefType(void); ReplaceOneLevelTypedefType(const ReplaceOneLevelTypedefType &); void operator=(const ReplaceOneLevelTypedefType &); }; #endif cvise-2.3.0/clang_delta/ReplaceSimpleTypedef.cpp000066400000000000000000000147121402162750500216430ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceSimpleTypedef.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass replaces typedef names with the underlying type if the \ underlying type falls into one of the following categories: \ * scalar type; \n\ * union; \n\ * non-templated class; \n\ * pointer to scalar type\n"; static RegisterTransformation Trans("replace-simple-typedef", DescriptionMsg); class ReplaceSimpleTypedefCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceSimpleTypedefCollectionVisitor(ReplaceSimpleTypedef *Instance) : ConsumerInstance(Instance) { } bool VisitTypedefDecl(TypedefDecl *D); private: ReplaceSimpleTypedef *ConsumerInstance; }; class ReplaceSimpleTypedefRewriteVisitor : public RecursiveASTVisitor { public: explicit ReplaceSimpleTypedefRewriteVisitor(ReplaceSimpleTypedef *Instance) : ConsumerInstance(Instance) { } bool VisitTypedefTypeLoc(TypedefTypeLoc Loc); bool VisitElaboratedTypeLoc(ElaboratedTypeLoc Loc); private: ReplaceSimpleTypedef *ConsumerInstance; }; bool ReplaceSimpleTypedefCollectionVisitor::VisitTypedefDecl(TypedefDecl *TdefD) { if (ConsumerInstance->isInIncludedFile(TdefD)) return true; TypedefDecl *CanonicalD = dyn_cast(TdefD->getCanonicalDecl()); if (!ConsumerInstance->VisitedTypedefDecls.count(CanonicalD)) { ConsumerInstance->handleOneTypedefDecl(CanonicalD); ConsumerInstance->VisitedTypedefDecls.insert(CanonicalD); } return true; } bool ReplaceSimpleTypedefRewriteVisitor::VisitTypedefTypeLoc(TypedefTypeLoc Loc) { if (ConsumerInstance->isInIncludedFile(Loc.getBeginLoc())) return true; const TypedefType *TdefTy = Loc.getTypePtr(); const TypedefDecl *TdefD = dyn_cast(TdefTy->getDecl()); if (!TdefD || TdefD->getBeginLoc().isInvalid()) return true; if (dyn_cast(TdefD->getCanonicalDecl()) == ConsumerInstance->TheTypedefDecl) { SourceRange Range = Loc.getSourceRange(); ConsumerInstance->TheRewriter.ReplaceText(Range, ConsumerInstance->TyName); ConsumerInstance->Rewritten = true; } return true; } // Handle cases like: // struct S { // typedef int Int; // }; // S::Int g; // where S::Int is referred as an ElaboratedType bool ReplaceSimpleTypedefRewriteVisitor::VisitElaboratedTypeLoc( ElaboratedTypeLoc Loc) { const ElaboratedType *ETy = dyn_cast(Loc.getTypePtr()); const Type *NamedTy = ETy->getNamedType().getTypePtr(); const TypedefType *TdefTy = NamedTy->getAs(); if (!TdefTy) return true; const TypedefDecl *TdefD = dyn_cast(TdefTy->getDecl()); if (!TdefD || (dyn_cast(TdefD->getCanonicalDecl()) != ConsumerInstance->TheTypedefDecl)) { return true; } NestedNameSpecifierLoc QualifierLoc = Loc.getQualifierLoc(); if (QualifierLoc && ConsumerInstance->IsScalarType) { ConsumerInstance->TheRewriter.RemoveText(QualifierLoc.getSourceRange()); ConsumerInstance->Rewritten = true; } return true; } void ReplaceSimpleTypedef::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceSimpleTypedefCollectionVisitor(this); RewriteVisitor = new ReplaceSimpleTypedefRewriteVisitor(this); } void ReplaceSimpleTypedef::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheTypedefDecl && "NULL TheTypedefDecl!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); removeTypedefs(); if (!Rewritten) { TransError = TransNoTextModificationError; return; } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceSimpleTypedef::removeTypedefs() { for (TypedefDecl::redecl_iterator I = TheTypedefDecl->redecls_begin(), E = TheTypedefDecl->redecls_end(); I != E; ++I) { SourceRange Range = (*I)->getSourceRange(); if (Range.isValid()) { RewriteHelper->removeTextUntil(Range, ';'); Rewritten = true; } } } bool ReplaceSimpleTypedef::isValidType(const Type *Ty, const TypedefDecl *D) { if (Ty->isEnumeralType() || Ty->isUnionType()) return true; if (const RecordType *RDTy = Ty->getAs()) { const RecordDecl *RD = RDTy->getDecl(); // omit some trivial cases, e.g., // typedef struct S { int x; } S; if (RD->getNameAsString() == D->getNameAsString()) return false; if (TransformationManager::isCLangOpt()) return true; const CXXRecordDecl *CXXRD = dyn_cast(RD); TransAssert(CXXRD && "NULL CXXRecordDecl!"); return (CXXRD->getDescribedClassTemplate() == NULL); } if (Ty->isPointerType()) Ty = getBasePointerElemType(Ty); if (Ty->isScalarType()) { IsScalarType = true; return true; } return false; } void ReplaceSimpleTypedef::handleOneTypedefDecl(const TypedefDecl *CanonicalD) { // omit some typedefs injected by Clang if (CanonicalD->getBeginLoc().isInvalid()) return; FullSourceLoc FullLoc = Context->getFullLoc(CanonicalD->getBeginLoc()); if (FullLoc.isInSystemHeader()) return; const Type *Ty = CanonicalD->getUnderlyingType().getTypePtr(); if (!isValidType(Ty, CanonicalD)) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheTypedefDecl = CanonicalD; CanonicalD->getUnderlyingType().getAsStringInternal(TyName, Context->getPrintingPolicy()); } } ReplaceSimpleTypedef::~ReplaceSimpleTypedef(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/ReplaceSimpleTypedef.h000066400000000000000000000034751402162750500213140ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_SIMPLE_TYPEDEF_H #define REPLACE_SIMPLE_TYPEDEF_H #include "Transformation.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; class TypedefDecl; } class ReplaceSimpleTypedefCollectionVisitor; class ReplaceSimpleTypedefRewriteVisitor; class ReplaceSimpleTypedef : public Transformation { friend class ReplaceSimpleTypedefCollectionVisitor; friend class ReplaceSimpleTypedefRewriteVisitor; public: ReplaceSimpleTypedef(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TyName(""), IsScalarType(false) {} ~ReplaceSimpleTypedef(); private: typedef llvm::SmallPtrSet TypedefDeclsSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneTypedefDecl(const clang::TypedefDecl *CanonicalD); bool isValidType(const clang::Type *Ty, const clang::TypedefDecl *D); void removeTypedefs(); TypedefDeclsSet VisitedTypedefDecls; ReplaceSimpleTypedefCollectionVisitor *CollectionVisitor; ReplaceSimpleTypedefRewriteVisitor *RewriteVisitor; const clang::TypedefDecl *TheTypedefDecl; std::string TyName; bool IsScalarType; // Unimplemented ReplaceSimpleTypedef(); ReplaceSimpleTypedef(const ReplaceSimpleTypedef &); void operator=(const ReplaceSimpleTypedef &); }; #endif cvise-2.3.0/clang_delta/ReplaceUndefinedFunction.cpp000066400000000000000000000117301402162750500224750ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReplaceUndefinedFunction.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "If there are more than one undefined function with the same type,\ pick up one and then replace all others with the selected one. \n"; static RegisterTransformation Trans("replace-undefined-function", DescriptionMsg); class ReplaceUndefFuncCollectionVisitor : public RecursiveASTVisitor { public: explicit ReplaceUndefFuncCollectionVisitor(ReplaceUndefinedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ReplaceUndefinedFunction *ConsumerInstance; }; class ReplaceUndefFuncRewriteVisitor : public RecursiveASTVisitor { public: explicit ReplaceUndefFuncRewriteVisitor(ReplaceUndefinedFunction *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitCallExpr(CallExpr *CE); private: ReplaceUndefinedFunction *ConsumerInstance; }; bool ReplaceUndefFuncCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || FD->hasBody()) return true; ConsumerInstance->handleOneFunctionDecl(FD->getCanonicalDecl()); return true; } bool ReplaceUndefFuncRewriteVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (FD->getCanonicalDecl() != ConsumerInstance->ReplacedFunctionDecl) return true; TransAssert(!FD->hasBody() && "FD cannot have any definition!"); ConsumerInstance->RewriteHelper->removeDecl(FD); return true; } bool ReplaceUndefFuncRewriteVisitor::VisitCallExpr(CallExpr *CE) { FunctionDecl *FD = CE->getDirectCallee(); // skip CXXMethodDecl for now if (!FD || dyn_cast(FD)) return true; if (FD->getCanonicalDecl() == ConsumerInstance->ReplacedFunctionDecl) { ConsumerInstance->TheRewriter.ReplaceText(CE->getBeginLoc(), ConsumerInstance->ReplacedFunctionDecl->getNameAsString().size(), ConsumerInstance->ReplacingFunctionDecl->getNameAsString()); } return true; } void ReplaceUndefinedFunction::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceUndefFuncCollectionVisitor(this); RewriteVisitor = new ReplaceUndefFuncRewriteVisitor(this); } void ReplaceUndefinedFunction::HandleTranslationUnit(ASTContext &Ctx) { TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void ReplaceUndefinedFunction::doAnalysis(void) { for (FunctionSetMap::iterator I = ReplaceableFunctions.begin(), E = ReplaceableFunctions.end(); I != E; ++I) { const FunctionDeclSet *FDSet = (*I).second; if (!FDSet) continue; for (FunctionDeclSet::iterator FI = FDSet->begin(), FE = FDSet->end(); FI != FE; ++FI) { ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { ReplacingFunctionDecl = (*I).first; ReplacedFunctionDecl = (*FI); } } } } void ReplaceUndefinedFunction::handleOneFunctionDecl(const FunctionDecl *FD) { QualType FDQualTy = FD->getType(); for (FunctionSetMap::iterator I = ReplaceableFunctions.begin(), E = ReplaceableFunctions.end(); I != E; ++I) { const FunctionDecl *ReplaceableFD = (*I).first; FunctionDeclSet *FDSet = (*I).second; QualType QualTy = ReplaceableFD->getType(); if (!Context->hasSameType(FDQualTy, QualTy)) continue; TransAssert(FDSet && "NULL FDSet"); FDSet->insert(FD); return; } FunctionDeclSet *FDSet = new FunctionDeclSet(); ReplaceableFunctions[FD] = FDSet; } ReplaceUndefinedFunction::~ReplaceUndefinedFunction(void) { delete CollectionVisitor; delete RewriteVisitor; for (FunctionSetMap::iterator I = ReplaceableFunctions.begin(), E = ReplaceableFunctions.end(); I != E; ++I) { const FunctionDeclSet *FDSet = (*I).second; delete FDSet; } } cvise-2.3.0/clang_delta/ReplaceUndefinedFunction.h000066400000000000000000000037151402162750500221460ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REPLACE_UNDEFINED_FUNCTION_H #define REPLACE_UNDEFINED_FUNCTION_H #include #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; } class ReplaceUndefFuncCollectionVisitor; class ReplaceUndefFuncRewriteVisitor; class ReplaceUndefinedFunction : public Transformation { friend class ReplaceUndefFuncCollectionVisitor; friend class ReplaceUndefFuncRewriteVisitor; public: ReplaceUndefinedFunction(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), ReplacingFunctionDecl(NULL), ReplacedFunctionDecl(NULL) { } ~ReplaceUndefinedFunction(void); private: typedef llvm::SetVector FunctionDeclSet; typedef llvm::MapVector FunctionSetMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneFunctionDecl(const clang::FunctionDecl *FD); void doAnalysis(void); FunctionSetMap ReplaceableFunctions; ReplaceUndefFuncCollectionVisitor *CollectionVisitor; ReplaceUndefFuncRewriteVisitor *RewriteVisitor; const clang::FunctionDecl *ReplacingFunctionDecl; const clang::FunctionDecl *ReplacedFunctionDecl; // Unimplemented ReplaceUndefinedFunction(void); ReplaceUndefinedFunction(const ReplaceUndefinedFunction &); void operator=(const ReplaceUndefinedFunction &); }; #endif cvise-2.3.0/clang_delta/ReturnVoid.cpp000066400000000000000000000171331402162750500176760ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "ReturnVoid.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Make a function return void. \ Only change the prototype of the function and \ delete all return statements in the function, \ but skip the call sites of this function.\n"; static RegisterTransformation Trans("return-void", DescriptionMsg); class RVASTVisitor : public RecursiveASTVisitor { public: explicit RVASTVisitor(ReturnVoid *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitReturnStmt(ReturnStmt *RS); private: ReturnVoid *ConsumerInstance; bool rewriteFuncDecl(FunctionDecl *FP); bool rewriteReturnStmt(ReturnStmt *RS); }; class RVCollectionVisitor : public RecursiveASTVisitor { public: explicit RVCollectionVisitor(ReturnVoid *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: ReturnVoid *ConsumerInstance; }; bool RVCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD)) return true; FunctionDecl *CanonicalDecl = FD->getCanonicalDecl(); if (ConsumerInstance->isNonVoidReturnFunction(CanonicalDecl)) { ConsumerInstance->ValidInstanceNum++; ConsumerInstance->ValidFuncDecls.push_back(CanonicalDecl); if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) ConsumerInstance->TheFuncDecl = CanonicalDecl; } if ((ConsumerInstance->TheFuncDecl == CanonicalDecl) && FD->isThisDeclarationADefinition()) ConsumerInstance->keepFuncDefRange(FD); return true; } void ReturnVoid::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new RVCollectionVisitor(this); TransformationASTVisitor = new RVASTVisitor(this); } bool ReturnVoid::isNonVoidReturnFunction(FunctionDecl *FD) { // Avoid duplications if (std::find(ValidFuncDecls.begin(), ValidFuncDecls.end(), FD) != ValidFuncDecls.end()) return false; // this function happen to have a library function, e.g. strcpy, // then the type source info won't be available, let's try to // get one from the one which is in the source if (!FD->getTypeSourceInfo()) { const FunctionDecl *FirstFD = FD->getCanonicalDecl(); FD = NULL; for (FunctionDecl::redecl_iterator I = FirstFD->redecls_begin(), E = FirstFD->redecls_end(); I != E; ++I) { if ((*I)->getTypeSourceInfo()) { FD = (*I); break; } } if (!FD) return false; } TypeLoc TLoc = FD->getTypeSourceInfo()->getTypeLoc(); SourceLocation SLoc = TLoc.getBeginLoc(); if (SLoc.isInvalid()) return false; QualType RVType = FD->getReturnType(); return !(RVType.getTypePtr()->isVoidType()); } void ReturnVoid::keepFuncDefRange(FunctionDecl *FD) { TransAssert(!FuncDefStartPos && !FuncDefEndPos && "Duplicated function definition?"); SourceRange FuncDefRange = FD->getSourceRange(); SourceLocation StartLoc = FuncDefRange.getBegin(); if (StartLoc.isMacroID()) { StartLoc = SrcManager->getExpansionLoc(StartLoc); } FuncDefStartPos = SrcManager->getCharacterData(StartLoc); SourceLocation EndLoc = FuncDefRange.getEnd(); FuncDefEndPos = SrcManager->getCharacterData(EndLoc); } bool ReturnVoid::isInTheFuncDef(ReturnStmt *RS) { // The candidate function doesn't have a body if (!FuncDefStartPos) return false; SourceRange RSRange = RS->getSourceRange(); SourceLocation StartLoc = RSRange.getBegin(); if (StartLoc.isMacroID()) { StartLoc = SrcManager->getExpansionLoc(StartLoc); } SourceLocation EndLoc = RSRange.getEnd(); if (EndLoc.isMacroID()) { EndLoc = SrcManager->getExpansionLoc(EndLoc); } const char *StartPos = SrcManager->getCharacterData(StartLoc); const char *EndPos = SrcManager->getCharacterData(EndLoc); (void)EndPos; if ((StartPos > FuncDefStartPos) && (StartPos < FuncDefEndPos)) { TransAssert((EndPos > FuncDefStartPos) && (EndPos < FuncDefEndPos) && "Bad return statement range!"); return true; } return false; } void ReturnVoid::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TransformationASTVisitor && "NULL TransformationASTVisitor!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFuncDecl && "NULL TheFuncDecl!"); TransformationASTVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (!Rewritten) { TransError = TransNoTextModificationError; return; } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool RVASTVisitor::rewriteFuncDecl(FunctionDecl *FD) { DeclarationNameInfo NameInfo = FD->getNameInfo(); SourceLocation NameInfoStartLoc = NameInfo.getBeginLoc(); SourceRange FuncDefRange = FD->getSourceRange(); SourceLocation FuncStartLoc = FuncDefRange.getBegin(); if (FuncStartLoc.isMacroID()) { FuncStartLoc = ConsumerInstance->SrcManager->getExpansionLoc(FuncStartLoc); } const char *FuncStartBuf = ConsumerInstance->SrcManager->getCharacterData(FuncStartLoc); const char *NameInfoStartBuf = ConsumerInstance->SrcManager->getCharacterData(NameInfoStartLoc); if (FuncStartBuf == NameInfoStartBuf) { ConsumerInstance->Rewritten = true; return !(ConsumerInstance->TheRewriter.InsertText(FuncStartLoc, "void ")); } int Offset = NameInfoStartBuf - FuncStartBuf; NameInfoStartBuf--; while ((*NameInfoStartBuf == '(') || (*NameInfoStartBuf == ' ') || (*NameInfoStartBuf == '\t') || (*NameInfoStartBuf == '\n')) { Offset--; NameInfoStartBuf--; } TransAssert(Offset >= 0); ConsumerInstance->Rewritten = true; return !(ConsumerInstance->TheRewriter.ReplaceText(FuncStartLoc, Offset, "void ")); } bool RVASTVisitor::rewriteReturnStmt(ReturnStmt *RS) { // SourceRange RSRange = RS->getSourceRange(); // return !(ConsumerInstance->TheRewriter.ReplaceText(RSRange, "return")); // Instead of replace an entire ReturnStmt with return, let's keep Ret Expr. // The reason is that RetExpr could have side-effects and these side-effects // could cause bugs. But we still could remove "return" keyword ConsumerInstance->Rewritten = true; SourceLocation Loc = RS->getReturnLoc(); return !(ConsumerInstance->TheRewriter.RemoveText(Loc, 6)); } bool RVASTVisitor::VisitFunctionDecl(FunctionDecl *FD) { FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (CanonicalFD == ConsumerInstance->TheFuncDecl) return rewriteFuncDecl(FD); return true; } bool RVASTVisitor::VisitReturnStmt(ReturnStmt *RS) { if (ConsumerInstance->isInTheFuncDef(RS)) return rewriteReturnStmt(RS); return true; } ReturnVoid::~ReturnVoid(void) { delete CollectionVisitor; delete TransformationASTVisitor; } cvise-2.3.0/clang_delta/ReturnVoid.h000066400000000000000000000032241402162750500173370ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef VOID_RETURN_H #define VOID_RETURN_H #include #include "llvm/ADT/SmallVector.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class ReturnStmt; } class RVASTVisitor; class RVCollectionVisitor; class ReturnVoid : public Transformation { friend class RVASTVisitor; friend class RVCollectionVisitor; public: ReturnVoid(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TransformationASTVisitor(NULL), TheFuncDecl(NULL), FuncDefStartPos(NULL), FuncDefEndPos(NULL) { } ~ReturnVoid(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void keepFuncDefRange(clang::FunctionDecl *FD); bool isNonVoidReturnFunction(clang::FunctionDecl *FD); bool isInTheFuncDef(clang::ReturnStmt *RS); RVCollectionVisitor *CollectionVisitor; RVASTVisitor *TransformationASTVisitor; llvm::SmallVector ValidFuncDecls; clang::FunctionDecl *TheFuncDecl; const char *FuncDefStartPos; const char *FuncDefEndPos; // Unimplemented ReturnVoid(void); ReturnVoid(const ReturnVoid &); void operator=(const ReturnVoid &); }; #endif cvise-2.3.0/clang_delta/RewriteUtils.cpp000066400000000000000000001643771402162750500202540ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "RewriteUtils.h" #include #include #include "clang/Basic/SourceManager.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/ExprCXX.h" using namespace clang; static const char *DefaultIndentStr = " "; RewriteUtils *RewriteUtils::Instance; const char *RewriteUtils::TmpVarNamePrefix = "__trans_tmp_"; RewriteUtils *RewriteUtils::GetInstance(Rewriter *RW) { if (RewriteUtils::Instance) { RewriteUtils::Instance->TheRewriter = RW; RewriteUtils::Instance->SrcManager = &(RW->getSourceMgr()); return RewriteUtils::Instance; } RewriteUtils::Instance = new RewriteUtils(); assert(RewriteUtils::Instance); RewriteUtils::Instance->TheRewriter = RW; RewriteUtils::Instance->SrcManager = &(RW->getSourceMgr()); return RewriteUtils::Instance; } void RewriteUtils::Finalize(void) { if (RewriteUtils::Instance) { delete RewriteUtils::Instance; RewriteUtils::Instance = NULL; } } SourceLocation RewriteUtils::getRealLocation(SourceLocation Loc) { if (Loc.isMacroID()) { return SrcManager->getExpansionLoc(Loc); } return Loc; } SourceRange RewriteUtils::getRealSourceRange(SourceRange Range) { SourceLocation StartLoc = Range.getBegin(); SourceLocation EndLoc = Range.getEnd(); return SourceRange(getRealLocation(StartLoc), getRealLocation(EndLoc)); } // copied from Rewriter.cpp unsigned RewriteUtils::getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID, SourceManager *SrcManager) { assert(Loc.isValid() && "Invalid location"); std::pair V = SrcManager->getDecomposedLoc(Loc); FID = V.first; return V.second; } unsigned RewriteUtils::getOffsetBetweenLocations(SourceLocation StartLoc, SourceLocation EndLoc, SourceManager *SrcManager) { FileID FID; unsigned StartOffset = getLocationOffsetAndFileID(StartLoc, FID, SrcManager); unsigned EndOffset = getLocationOffsetAndFileID(EndLoc, FID, SrcManager); TransAssert((EndOffset >= StartOffset) && "Bad locations!"); return (EndOffset - StartOffset); } SourceLocation RewriteUtils::getEndLocationFromBegin(SourceRange Range) { SourceLocation StartLoc = Range.getBegin(); SourceLocation EndLoc = Range.getEnd(); if (StartLoc.isInvalid()) return StartLoc; if (EndLoc.isInvalid()) return EndLoc; if (StartLoc.isMacroID()) StartLoc = SrcManager->getFileLoc(StartLoc); if (EndLoc.isMacroID()) EndLoc = SrcManager->getFileLoc(EndLoc); SourceRange NewRange(StartLoc, EndLoc); int LocRangeSize = TheRewriter->getRangeSize(NewRange); if (LocRangeSize == -1) return NewRange.getEnd(); return StartLoc.getLocWithOffset(LocRangeSize); } int RewriteUtils::getOffsetUntil(const char *Buf, char Symbol) { int Offset = 0; while (*Buf != Symbol) { Buf++; if (*Buf == '\0') break; Offset++; } return Offset; } int RewriteUtils::getSkippingOffset(const char *Buf, char Symbol) { int Offset = 0; while (*Buf == Symbol) { Buf++; if (*Buf == '\0') break; Offset++; } return Offset; } SourceLocation RewriteUtils::getEndLocationUntil(SourceRange Range, char Symbol) { SourceLocation EndLoc = getEndLocationFromBegin(Range); if (EndLoc.isInvalid()) return EndLoc; const char *EndBuf = SrcManager->getCharacterData(EndLoc); int Offset = getOffsetUntil(EndBuf, Symbol); return EndLoc.getLocWithOffset(Offset); } SourceLocation RewriteUtils::getLocationUntil(SourceLocation Loc, char Symbol) { const char *Buf = SrcManager->getCharacterData(Loc); int Offset = getOffsetUntil(Buf, Symbol); return Loc.getLocWithOffset(Offset); } SourceLocation RewriteUtils::getEndLocationAfter(SourceRange Range, char Symbol) { SourceLocation EndLoc = getEndLocationFromBegin(Range); if (EndLoc.isInvalid()) return EndLoc; const char *EndBuf = SrcManager->getCharacterData(EndLoc); int Offset = getOffsetUntil(EndBuf, Symbol); Offset++; return EndLoc.getLocWithOffset(Offset); } SourceLocation RewriteUtils::getLocationAfter(SourceLocation Loc, char Symbol) { const char *Buf = SrcManager->getCharacterData(Loc); int Offset = getOffsetUntil(Buf, Symbol); Offset++; return Loc.getLocWithOffset(Offset); } SourceLocation RewriteUtils::getLocationAfterSkiping(SourceLocation StartLoc, char Symbol) { const char *StartBuf = SrcManager->getCharacterData(StartLoc); int Offset = getSkippingOffset(StartBuf, Symbol); return StartLoc.getLocWithOffset(Offset); } SourceLocation RewriteUtils::getParamSubstringLocation(SourceLocation StartLoc, size_t Size, const std::string &Substr) { const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::string TmpStr(StartBuf, Size); size_t Pos = TmpStr.find(Substr); TransAssert((Pos != std::string::npos) && "Bad Name Position!"); if (Pos == 0) return StartLoc; else return StartLoc.getLocWithOffset(Pos); } bool RewriteUtils::removeParamFromFuncDecl(const ParmVarDecl *PV, unsigned int NumParams, int ParamPos) { SourceRange ParamLocRange = PV->getSourceRange(); int RangeSize; SourceLocation StartLoc = ParamLocRange.getBegin(); if (StartLoc.isMacroID()) StartLoc = SrcManager->getExpansionLoc(StartLoc); SourceLocation EndLoc = ParamLocRange.getEnd(); if (EndLoc.isMacroID()) EndLoc = SrcManager->getExpansionLoc(EndLoc); if (StartLoc.isInvalid() && EndLoc.isInvalid()) { return false; } else if (StartLoc.isInvalid()) { StartLoc = EndLoc; RangeSize = PV->getNameAsString().size(); } else if (EndLoc.isInvalid()) { const char *Buf = SrcManager->getCharacterData(StartLoc); if ((ParamPos == 0) && (NumParams == 1)) { RangeSize = getOffsetUntil(Buf, ')'); } else { RangeSize = getOffsetUntil(Buf, ','); } } else { RangeSize = TheRewriter->getRangeSize(SourceRange(StartLoc, EndLoc)); if (RangeSize == -1) return false; } // The param is the only parameter of the function declaration. // Replace it with void if ((ParamPos == 0) && (NumParams == 1)) { return !(TheRewriter->ReplaceText(StartLoc, RangeSize, "void")); } // The param is the last parameter if (ParamPos == static_cast(NumParams - 1)) { int Offset = 0; const char *StartBuf = SrcManager->getCharacterData(StartLoc); TransAssert(StartBuf && "Invalid start buffer!"); while (*StartBuf != ',') { StartBuf--; Offset--; } SourceLocation NewStartLoc = StartLoc.getLocWithOffset(Offset); return !(TheRewriter->RemoveText(NewStartLoc, RangeSize - Offset)); } // We cannot use the code below: // SourceLocation EndLoc = ParamLocRange.getEnd(); // const char *EndBuf = // ConsumerInstance->SrcManager->getCharacterData(EndLoc); // Because getEnd() returns the start of the last token if this // is a token range. For example, in the above example, // getEnd() points to the start of "x" // See the comments on getRangeSize in clang/lib/Rewriter/Rewriter.cpp int NewRangeSize = 0; const char *StartBuf = SrcManager->getCharacterData(StartLoc); while (NewRangeSize < RangeSize) { StartBuf++; NewRangeSize++; } TransAssert(StartBuf && "Invalid start buffer!"); // FIXME: This isn't really correct for processing old-style function // declarations, but just let's live with it for now. while (*StartBuf != ',' && *StartBuf != ';') { StartBuf++; NewRangeSize++; } return !(TheRewriter->RemoveText(StartLoc, NewRangeSize + 1)); } // Handle CXXConstructExpr and CallExpr. // These two do not inherit each other, and we need a couple of // `common` member functions from them. // Is this too ugly? Any better way to do this? const Expr *RewriteUtils::getArgWrapper(const Expr *E, int ParamPos) { const CXXConstructExpr *CtorE = dyn_cast(E); if (CtorE) return CtorE->getArg(ParamPos); const CallExpr *CE = dyn_cast(E); if (CE) return CE->getArg(ParamPos); TransAssert(0 && "Invalid Expr!"); return NULL; } unsigned RewriteUtils::getNumArgsWrapper(const Expr *E) { const CXXConstructExpr *CtorE = dyn_cast(E); if (CtorE) return CtorE->getNumArgs(); const CallExpr *CE = dyn_cast(E); if (CE) return CE->getNumArgs(); TransAssert(0 && "Invalid Expr!"); return 0; } bool RewriteUtils::removeArgFromExpr(const Expr *E, int ParamPos) { if (ParamPos >= static_cast(getNumArgsWrapper(E))) return true; const Expr *Arg = getArgWrapper(E, ParamPos); TransAssert(Arg && "Null arg!"); if (dyn_cast(Arg->IgnoreParenCasts())) return true; SourceRange ArgRange = Arg->getSourceRange(); int RangeSize = TheRewriter->getRangeSize(ArgRange); if (RangeSize == -1) return false; SourceLocation StartLoc = ArgRange.getBegin(); unsigned int NumArgs = getNumArgsWrapper(E); if ((ParamPos == 0) && ((NumArgs == 1) || ((NumArgs > 1) && dyn_cast( getArgWrapper(E, 1)->IgnoreParenCasts())))) { // Note that ')' is included in ParamLocRange return !(TheRewriter->RemoveText(ArgRange)); } int LastArgPos = static_cast(NumArgs - 1); // The param is the last non-default parameter if ((ParamPos == LastArgPos) || ((ParamPos < LastArgPos) && dyn_cast( getArgWrapper(E, ParamPos+1)->IgnoreParenCasts()))) { int Offset = 0; const char *StartBuf = SrcManager->getCharacterData(StartLoc); TransAssert(StartBuf && "Invalid start buffer!"); while (*StartBuf != ',') { StartBuf--; Offset--; } SourceLocation NewStartLoc = StartLoc.getLocWithOffset(Offset); return !(TheRewriter->RemoveText(NewStartLoc, RangeSize - Offset)); } // We cannot use SrcManager->getCharacterData(StartLoc) to get the buffer, // because it returns the unmodified string. I've tried to use // getEndlocationUntil(ArgRange, ",", ...) call, but still failed. // Seems in some cases, it returns bad results for a complex case like: // foo(...foo(...), ...) // So I ended up with this ugly way - get the end loc from the next arg. const Expr *NextArg = getArgWrapper(E, ParamPos+1); SourceRange NextArgRange = NextArg->getSourceRange(); SourceLocation NextStartLoc = NextArgRange.getBegin(); const char *NextStartBuf = SrcManager->getCharacterData(NextStartLoc); int Offset = 0; while (*NextStartBuf != ',') { NextStartBuf--; Offset--; } SourceLocation NewEndLoc = NextStartLoc.getLocWithOffset(Offset); return !TheRewriter->RemoveText(SourceRange(StartLoc, NewEndLoc)); } bool RewriteUtils::removeArgFromCXXConstructExpr(const CXXConstructExpr *CE, int ParamPos) { return removeArgFromExpr(CE, ParamPos); } bool RewriteUtils::removeArgFromCallExpr(const CallExpr *CallE, int ParamPos) { return removeArgFromExpr(CallE, ParamPos); } void RewriteUtils::skipRangeByType(const std::string &BufStr, const Type *Ty, int &Offset) { Offset = 0; int BufSz = static_cast(BufStr.size()); size_t Pos; while (Offset < BufSz) { if (isspace(BufStr[Offset])) { Offset++; continue; } Pos = BufStr.find("char", Offset); if (Pos != std::string::npos) { Offset += 4; continue; } Pos = BufStr.find("int", Offset); if (Pos != std::string::npos) { Offset += 3; continue; } Pos = BufStr.find("short", Offset); if (Pos != std::string::npos) { Offset += 5; continue; } Pos = BufStr.find("long", Offset); if (Pos != std::string::npos) { Offset += 4; continue; } return; } } SourceLocation RewriteUtils::skipPossibleTypeRange(const Type *Ty, SourceLocation OrigEndLoc, SourceLocation VarStartLoc) { if (!Ty->isIntegerType()) return OrigEndLoc; int Offset; std::string BufStr; getStringBetweenLocs(BufStr, OrigEndLoc, VarStartLoc); skipRangeByType(BufStr, Ty, Offset); return OrigEndLoc.getLocWithOffset(Offset); } SourceLocation RewriteUtils::getVarDeclTypeLocBegin(const VarDecl *VD) { TypeLoc VarTypeLoc = VD->getTypeSourceInfo()->getTypeLoc(); TypeLoc NextTL = VarTypeLoc.getNextTypeLoc(); while (!NextTL.isNull()) { VarTypeLoc = NextTL; NextTL = NextTL.getNextTypeLoc(); } return VarTypeLoc.getBeginLoc(); } SourceLocation RewriteUtils::getVarDeclTypeLocEnd(const VarDecl *VD) { TypeLoc VarTypeLoc = VD->getTypeSourceInfo()->getTypeLoc(); const IdentifierInfo *Id = VD->getType().getBaseTypeIdentifier(); // handle a special case shown as below: // x; // *y[]; // (*z)[]; // void foo(void) {...} // where x implicitly has type of int, whereas y has type of int * if (!Id) { SourceLocation EndLoc = VD->getLocation(); const char *Buf = SrcManager->getCharacterData(EndLoc); int Offset = -1; SourceLocation NewEndLoc = EndLoc.getLocWithOffset(Offset); if (!NewEndLoc.isValid()) return EndLoc; Buf--; while (isspace(*Buf) || (*Buf == '*') || (*Buf == '(')) { Offset--; NewEndLoc = EndLoc.getLocWithOffset(Offset); if (!NewEndLoc.isValid()) return EndLoc.getLocWithOffset(Offset+1); Buf--; } return EndLoc.getLocWithOffset(Offset+1); } TypeLoc NextTL = VarTypeLoc.getNextTypeLoc(); while (!NextTL.isNull()) { VarTypeLoc = NextTL; NextTL = NextTL.getNextTypeLoc(); } SourceRange TypeLocRange = VarTypeLoc.getSourceRange(); SourceLocation EndLoc = getEndLocationFromBegin(TypeLocRange); TransAssert(EndLoc.isValid() && "Invalid EndLoc!"); const Type *Ty = VarTypeLoc.getTypePtr(); // I am not sure why, but for a declaration like below: // unsigned int a; (or long long a;) // TypeLoc.getBeginLoc() returns the position of 'u' // TypeLoc.getEndLoc() also returns the position of 'u' // The size of TypeLoc.getSourceRange() is 8, which is the // length of "unsigned" // Then we are getting trouble, because now EndLoc is right // after 'd', but we need it points to the location after "int". // skipPossibleTypeRange corrects the above deviation // Or am I doing something horrible here? EndLoc = skipPossibleTypeRange(Ty, EndLoc, VD->getLocation()); return EndLoc; } bool RewriteUtils::removeVarFromDeclStmt(DeclStmt *DS, const VarDecl *VD, Decl *PrevDecl, bool IsFirstDecl, bool *StmtRemoved) { SourceRange StmtRange = DS->getSourceRange(); // VD is the the only declaration, so it is safe to remove the entire stmt if (DS->isSingleDecl()) { return !(TheRewriter->RemoveText(getRealSourceRange(StmtRange))); } // handle the case where we could have implicit declaration of RecordDecl // e.g., // foo (void) { // struct S0 *s; // ...; // } // in this case, struct S0 is implicitly declared if (PrevDecl) { if ( RecordDecl *RD = dyn_cast(PrevDecl) ) { DeclGroup DGroup = DS->getDeclGroup().getDeclGroup(); IsFirstDecl = true; if ((!RD->getDefinition() || RD->getNameAsString() == "") && DGroup.size() == 2) { *StmtRemoved = true; return !(TheRewriter->RemoveText(StmtRange)); } } } SourceRange VarRange = VD->getSourceRange(); // VD is the first declaration in a declaration group. // We keep the leading type string if (IsFirstDecl) { // We need to get the outermost TypeLocEnd instead of the StartLoc of // a var name, because we need to handle the case below: // int *x, *y; // If we rely on the StartLoc of a var name, then we will make bad // transformation like: // int * *y; SourceLocation NewStartLoc = getVarDeclTypeLocEnd(VD); if (NewStartLoc.isMacroID()) { NewStartLoc = SrcManager->getSpellingLoc(NewStartLoc); const char *StartBuf = SrcManager->getCharacterData(NewStartLoc); // Make sure we have at least one space before the name. if (*StartBuf == ' ') NewStartLoc = NewStartLoc.getLocWithOffset(1); } SourceLocation NewEndLoc = getEndLocationUntil(VarRange, ','); if (NewEndLoc.isMacroID()) NewEndLoc = SrcManager->getSpellingLoc(NewEndLoc); return !(TheRewriter->RemoveText(SourceRange(NewStartLoc, NewEndLoc))); } TransAssert(PrevDecl && "PrevDecl cannot be NULL!"); SourceLocation VarEndLoc = VarRange.getEnd(); SourceRange PrevDeclRange = PrevDecl->getSourceRange(); SourceLocation PrevDeclEndLoc = getEndLocationUntil(PrevDeclRange, ','); if (VarEndLoc.isMacroID()) VarEndLoc = SrcManager->getSpellingLoc(VarEndLoc); if (PrevDeclEndLoc.isMacroID()) PrevDeclEndLoc = SrcManager->getSpellingLoc(PrevDeclEndLoc); return !(TheRewriter->RemoveText(SourceRange(PrevDeclEndLoc, VarEndLoc))); } bool RewriteUtils::getExprString(const Expr *E, std::string &ES) { SourceRange ExprRange = E->getSourceRange(); SourceLocation StartLoc = ExprRange.getBegin(); if (StartLoc.isInvalid() && !StartLoc.isMacroID()) { ES = ""; return false; } int RangeSize = TheRewriter->getRangeSize(ExprRange); if (RangeSize == -1) { if (StartLoc.isMacroID()) { StartLoc = SrcManager->getFileLoc(StartLoc); SourceLocation EndLoc = SrcManager->getFileLoc(ExprRange.getEnd()); RangeSize = TheRewriter->getRangeSize(SourceRange(StartLoc, EndLoc)); } else { ES = ""; return false; } } const char *StartBuf = SrcManager->getCharacterData(StartLoc); ES.assign(StartBuf, RangeSize); const BinaryOperator *BinOp = dyn_cast(E); // Keep the semantics of Comma operator if (BinOp && (BinOp->getOpcode() == BO_Comma)) ES = "(" + ES + ")"; return true; } bool RewriteUtils::getStmtString(const Stmt *S, std::string &Str) { SourceRange StmtRange = S->getSourceRange(); int RangeSize = TheRewriter->getRangeSize(StmtRange); if (RangeSize == -1) return false; SourceLocation StartLoc = StmtRange.getBegin(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); Str.assign(StartBuf, RangeSize); return true; } SourceLocation RewriteUtils::getExpansionEndLoc(SourceLocation EndLoc) { FileID FID = SrcManager->getFileID(EndLoc); const SrcMgr::SLocEntry *Entry = &SrcManager->getSLocEntry(FID); while (Entry->getExpansion().getExpansionLocStart().isMacroID()) { EndLoc = Entry->getExpansion().getExpansionLocStart(); FID = SrcManager->getFileID(EndLoc); Entry = &SrcManager->getSLocEntry(FID); } return Entry->getExpansion().getExpansionLocEnd(); } bool RewriteUtils::replaceExpr(const Expr *E, const std::string &ES) { SourceRange ExprRange = E->getSourceRange(); int RangeSize = TheRewriter->getRangeSize(ExprRange); if (RangeSize == -1) { SourceLocation StartLoc = ExprRange.getBegin(); if (SrcManager->isMacroBodyExpansion(StartLoc)) { StartLoc = SrcManager->getFileLoc(StartLoc); } SourceLocation EndLoc = ExprRange.getEnd(); if (SrcManager->isMacroBodyExpansion(EndLoc) || SrcManager->isMacroArgExpansion(EndLoc)) { // FIXME: handle cases below: // #define macro bar(1,2); // int bar(int p1, int p2) { return p1 + p2; } // void foo(void) { int x = macro } EndLoc = getExpansionEndLoc(EndLoc); } return !(TheRewriter->ReplaceText(SourceRange(StartLoc, EndLoc), ES)); } return !(TheRewriter->ReplaceText(ExprRange, ES)); } bool RewriteUtils::replaceExprNotInclude(const Expr *E, const std::string &ES) { SourceRange ExprRange = E->getSourceRange(); SourceLocation StartLoc = ExprRange.getBegin(); if (StartLoc.isMacroID()) { StartLoc = SrcManager->getFileLoc(StartLoc); SourceLocation EndLoc = ExprRange.getEnd(); TransAssert(EndLoc.isMacroID() && "EndLoc is not from a macro!"); ExprRange = SourceRange(StartLoc, SrcManager->getFileLoc(EndLoc)); } TransAssert((TheRewriter->getRangeSize(ExprRange) != -1) && "Bad expr range!"); Rewriter::RewriteOptions Opts; // We don't want to include the previously inserted string Opts.IncludeInsertsAtBeginOfRange = false; TheRewriter->RemoveText(ExprRange, Opts); return !(TheRewriter->InsertText(StartLoc, ES)); } std::string RewriteUtils::getStmtIndentString(Stmt *S, SourceManager *SrcManager) { SourceLocation StmtStartLoc = S->getBeginLoc(); if (StmtStartLoc.isMacroID()) { StmtStartLoc = SrcManager->getFileLoc(StmtStartLoc); } FileID FID; unsigned StartOffset = getLocationOffsetAndFileID(StmtStartLoc, FID, SrcManager); StringRef MB = SrcManager->getBufferData(FID); unsigned lineNo = SrcManager->getLineNumber(FID, StartOffset) - 1; #if LLVM_VERSION_MAJOR >= 12 const SrcMgr::ContentCache& Content = SrcManager->getSLocEntry(FID).getFile().getContentCache(); unsigned lineOffs = Content.SourceLineCache[lineNo]; #else const SrcMgr::ContentCache * Content = SrcManager->getSLocEntry(FID).getFile().getContentCache(); unsigned lineOffs = Content->SourceLineCache[lineNo]; #endif // Find the whitespace at the start of the line. StringRef indentSpace; unsigned I = lineOffs; while (isspace(MB[I])) ++I; indentSpace = MB.substr(lineOffs, I-lineOffs); return indentSpace.str(); } bool RewriteUtils::addLocalVarToFunc(const std::string &VarStr, FunctionDecl *FD) { Stmt *Body = FD->getBody(); TransAssert(Body && "NULL body for a function definition!"); std::string IndentStr; StmtIterator I = Body->child_begin(); if (I == Body->child_end()) IndentStr = DefaultIndentStr; else IndentStr = getStmtIndentString((*I), SrcManager); std::string NewVarStr = "\n" + IndentStr + VarStr; SourceLocation StartLoc = Body->getBeginLoc(); return !(TheRewriter->InsertTextAfterToken(StartLoc, NewVarStr)); } const char *RewriteUtils::getTmpVarNamePrefix(void) { return TmpVarNamePrefix; } bool RewriteUtils::addNewAssignStmtBefore(Stmt *BeforeStmt, const std::string &VarName, Expr *RHS, bool NeedParen) { std::string IndentStr = RewriteUtils::getStmtIndentString(BeforeStmt, SrcManager); if (NeedParen) { SourceRange StmtRange = BeforeStmt->getSourceRange(); SourceLocation LocEnd = RewriteUtils::getEndLocationFromBegin(StmtRange); TransAssert(LocEnd.isValid() && "Invalid LocEnd!"); std::string PostStr = "\n" + IndentStr + "}"; if (TheRewriter->InsertTextAfterToken(LocEnd, PostStr)) return false; } SourceLocation StmtLocStart = BeforeStmt->getBeginLoc(); if (StmtLocStart.isMacroID()) { StmtLocStart = SrcManager->getFileLoc(StmtLocStart); } std::string ExprStr; RewriteUtils::getExprString(RHS, ExprStr); std::string AssignStmtStr; if (NeedParen) { AssignStmtStr = "{\n"; AssignStmtStr += IndentStr + " " + VarName + " = "; AssignStmtStr += ExprStr; AssignStmtStr += ";\n" + IndentStr + " "; } else { AssignStmtStr = VarName + " = "; AssignStmtStr += ExprStr; AssignStmtStr += ";\n" + IndentStr; } return !(TheRewriter->InsertText(StmtLocStart, AssignStmtStr, /*InsertAfter=*/false)); } void RewriteUtils::indentAfterNewLine(StringRef Str, std::string &NewStr, const std::string &IndentStr) { SmallVector StrVec; Str.split(StrVec, "\n"); NewStr = ""; for(SmallVector::iterator I = StrVec.begin(), E = StrVec.end(); I != E; ++I) { NewStr += ((*I).str() + "\n" + IndentStr); } } void RewriteUtils::addOpenParenBeforeStmt(Stmt *S, const std::string &IndentStr) { SourceRange StmtRange = S->getSourceRange(); SourceLocation LocEnd = RewriteUtils::getEndLocationFromBegin(StmtRange); TransAssert(LocEnd.isValid() && "Invalid LocEnd!"); std::string PostStr = "\n" + IndentStr + "}"; TheRewriter->InsertTextAfterToken(LocEnd, PostStr); } bool RewriteUtils::addStringBeforeStmtInternal(Stmt *S, const std::string &Str, const std::string &IndentStr, bool NeedParen) { std::string NewStr; if (NeedParen) { NewStr = "{\n"; } NewStr += Str; NewStr += "\n"; std::string IndentedStr; indentAfterNewLine(NewStr, IndentedStr, IndentStr); return !(TheRewriter->InsertText(S->getBeginLoc(), IndentedStr, /*InsertAfter=*/false)); } bool RewriteUtils::addStringBeforeStmt(Stmt *BeforeStmt, const std::string &Str, bool NeedParen) { std::string IndentStr = RewriteUtils::getStmtIndentString(BeforeStmt, SrcManager); if (NeedParen) { addOpenParenBeforeStmt(BeforeStmt, IndentStr); } return addStringBeforeStmtInternal(BeforeStmt, Str, IndentStr, NeedParen); } // Note that we can't use addStringBeforeStmt because // we need to modify an expression in BeforeStmt. We have // to do rewrite from end to begin to avoid crash. bool RewriteUtils::addStringBeforeStmtAndReplaceExpr(Stmt *BeforeStmt, const std::string &StmtStr, const Expr *E, const std::string &ExprStr, bool NeedParen) { std::string IndentStr = RewriteUtils::getStmtIndentString(BeforeStmt, SrcManager); if (NeedParen) { addOpenParenBeforeStmt(BeforeStmt, IndentStr); } replaceExpr(E, ExprStr); return addStringBeforeStmtInternal(BeforeStmt, StmtStr, IndentStr, NeedParen); } bool RewriteUtils::addStringAfterStmt(Stmt *AfterStmt, const std::string &Str) { std::string IndentStr = RewriteUtils::getStmtIndentString(AfterStmt, SrcManager); std::string NewStr = "\n" + IndentStr + Str; SourceRange StmtRange = AfterStmt->getSourceRange(); SourceLocation LocEnd = RewriteUtils::getEndLocationFromBegin(StmtRange); TransAssert(LocEnd.isValid() && "Invalid LocEnd!"); return !(TheRewriter->InsertText(LocEnd, NewStr)); } bool RewriteUtils::addStringAfterVarDecl(const VarDecl *VD, const std::string &Str) { SourceRange VarRange = VD->getSourceRange(); SourceLocation LocEnd = getEndLocationAfter(VarRange, ';'); return !(TheRewriter->InsertText(LocEnd, "\n" + Str)); } bool RewriteUtils::addStringAfterFuncDecl(const FunctionDecl *FD, const std::string &Str) { SourceRange FDRange = FD->getSourceRange(); SourceLocation LocEnd = getEndLocationAfter(FDRange, ';'); return !(TheRewriter->InsertText(LocEnd, "\n" + Str)); } // This function is an experimental one. It doesn't work // if ND is a class of FunctionDecl, but I am not sure // how it works for other types of NamedDecls bool RewriteUtils::replaceNamedDeclName(const NamedDecl *ND, const std::string &NameStr) { TransAssert(!isa(ND) && "Please use replaceFunctionDeclName for renaming a FunctionDecl!"); TransAssert(!isa(ND) && "Cannot use this function for renaming UsingDirectiveDecl"); SourceLocation NameLocStart = ND->getLocation(); return !(TheRewriter->ReplaceText(NameLocStart, ND->getNameAsString().size(), NameStr)); } bool RewriteUtils::replaceValueDecl(const ValueDecl *VD, const std::string &Str) { SourceRange Range = VD->getSourceRange(); unsigned RangeSize = TheRewriter->getRangeSize(Range); return !(TheRewriter->ReplaceText(Range.getBegin(), RangeSize, Str)); } bool RewriteUtils::replaceVarDeclName(VarDecl *VD, const std::string &NameStr) { SourceLocation NameLocStart = VD->getLocation(); return !(TheRewriter->ReplaceText(NameLocStart, VD->getNameAsString().size(), NameStr)); } bool RewriteUtils::replaceFunctionDeclName(const FunctionDecl *FD, const std::string &NameStr) { // We cannot naively use FD->getNameAsString() here. // For example, for a template class // template // class SomeClass { // public: // SomeClass() {} // }; // applying getNameAsString() on SomeClass() gives us SomeClass. DeclarationNameInfo NameInfo = FD->getNameInfo(); DeclarationName DeclName = NameInfo.getName(); DeclarationName::NameKind K = DeclName.getNameKind(); TransAssert((K != DeclarationName::CXXDestructorName) && "Cannot rename CXXDestructorName here!"); std::string FDName = FD->getNameAsString(); size_t FDNameLen = FD->getNameAsString().length(); if (K == DeclarationName::CXXConstructorName) { const Type *Ty = DeclName.getCXXNameType().getTypePtr(); if (Ty->getTypeClass() == Type::InjectedClassName) { const CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl(); std::string RDName = CXXRD->getNameAsString(); FDNameLen = FDName.find(RDName); TransAssert((FDNameLen != std::string::npos) && "Cannot find RecordDecl Name!"); FDNameLen += RDName.length(); } } return !TheRewriter->ReplaceText(NameInfo.getLoc(), FDNameLen, NameStr); } bool RewriteUtils::replaceCXXDestructorDeclName( const CXXDestructorDecl *DtorDecl, const std::string &Name) { SourceLocation StartLoc = DtorDecl->getLocation(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); TransAssert((*StartBuf == '~') && "Invalid Destructor Location"); // FIXME: it's quite ugly, better to use clang's Lexer unsigned Off = 0; StartBuf++; while (isspace(*StartBuf)) { StartBuf++; Off++; } std::string DName = DtorDecl->getNameAsString(); DeclarationNameInfo NameInfo = DtorDecl->getNameInfo(); DeclarationName DeclName = NameInfo.getName(); const Type *Ty = DeclName.getCXXNameType().getTypePtr(); size_t NameLen; if (Ty->getTypeClass() == Type::InjectedClassName) { const CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl(); std::string RDName = CXXRD->getNameAsString(); NameLen = DName.find(RDName); TransAssert((NameLen != std::string::npos) && "Cannot find RecordDecl Name!"); NameLen += RDName.length(); } else { NameLen = DName.length(); } NameLen += Off; return !TheRewriter->ReplaceText(StartLoc, NameLen, "~" + Name); } bool RewriteUtils::replaceRecordDeclName(const RecordDecl *RD, const std::string &NameStr) { SourceLocation LocStart = RD->getLocation(); return !TheRewriter->ReplaceText(LocStart, RD->getNameAsString().length(), NameStr); } bool RewriteUtils::replaceRecordDeclDef(const RecordDecl *RD, const std::string &NameStr) { if (RD->isThisDeclarationADefinition()) { SourceLocation RBLoc = RD->getBraceRange().getEnd(); if (RBLoc.isInvalid()) { return !TheRewriter->ReplaceText(RD->getSourceRange(), NameStr); } else { SourceLocation StartLoc = RD->getSourceRange().getBegin(); return !TheRewriter->ReplaceText(SourceRange(StartLoc, RBLoc), NameStr); } } return true; } bool RewriteUtils::replaceVarTypeName(const VarDecl *VD, const std::string &NameStr) { const IdentifierInfo *TypeId = VD->getType().getBaseTypeIdentifier(); SourceLocation LocStart = getVarDeclTypeLocBegin(VD); return !TheRewriter->ReplaceText(LocStart, TypeId->getLength(), NameStr); } void RewriteUtils::getStringBetweenLocs(std::string &Str, SourceLocation LocStart, SourceLocation LocEnd) { const char *StartBuf = SrcManager->getCharacterData(LocStart); const char *EndBuf = SrcManager->getCharacterData(LocEnd); TransAssert(StartBuf < EndBuf); size_t Off = EndBuf - StartBuf; Str.assign(StartBuf, Off); } void RewriteUtils::getStringBetweenLocsAfterStart(std::string &Str, SourceLocation LocStart, SourceLocation LocEnd) { const char *StartBuf = SrcManager->getCharacterData(LocStart); const char *EndBuf = SrcManager->getCharacterData(LocEnd); StartBuf++; TransAssert(StartBuf <= EndBuf); size_t Off = EndBuf - StartBuf; Str.assign(StartBuf, Off); } bool RewriteUtils::getEntireDeclGroupStrAndRemove(DeclGroupRef DGR, std::string &Str) { Decl *FirstD, *LastD; if (DGR.isSingleDecl()) { FirstD = DGR.getSingleDecl(); LastD = FirstD; } else { DeclGroupRef::iterator I = DGR.begin(); FirstD = (*I); DeclGroupRef::iterator E = DGR.end(); --E; LastD = (*E); } SourceRange FirstRange = FirstD->getSourceRange(); SourceLocation StartLoc = FirstRange.getBegin(); SourceRange LastRange = LastD->getSourceRange(); SourceLocation EndLoc = getEndLocationUntil(LastRange, ';'); // This isn't really good, but if EndLoc is invalid, what can we do? if (EndLoc.isInvalid()) { unsigned Off = 0; const char *StartBuf = SrcManager->getCharacterData(StartLoc); while ((*StartBuf != '\n') && (*StartBuf != ';') && (*StartBuf != '\0')) { Off++; StartBuf++; } assert(Off && "Zero offset!"); EndLoc = StartLoc.getLocWithOffset(Off); } getStringBetweenLocs(Str, StartLoc, EndLoc); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); } // This function skips type specifiers bool RewriteUtils::getDeclGroupStrAndRemove(DeclGroupRef DGR, std::string &Str) { if (DGR.isSingleDecl()) { Decl *D = DGR.getSingleDecl(); VarDecl *VD = dyn_cast(D); TransAssert(VD && "Bad VarDecl!"); // We need to get the outermost TypeLocEnd instead of the StartLoc of // a var name, because we need to handle the case below: // int *x; // int *y; // If we rely on the StartLoc of a var name, then we will make bad // transformation like: // int *x, y; SourceLocation TypeLocEnd = getVarDeclTypeLocEnd(VD); if (TypeLocEnd.isMacroID()) TypeLocEnd = SrcManager->getFileLoc(TypeLocEnd); SourceRange VarRange = VD->getSourceRange(); SourceLocation LocEnd = getEndLocationUntil(VarRange, ';'); getStringBetweenLocs(Str, TypeLocEnd, LocEnd); SourceLocation StartLoc = VarRange.getBegin(); if (StartLoc.isMacroID()) StartLoc = SrcManager->getFileLoc(StartLoc); SourceLocation NewEndLoc = getLocationAfterSkiping(LocEnd, ';'); return !(TheRewriter->RemoveText(SourceRange(StartLoc, NewEndLoc))); } TransAssert(DGR.getDeclGroup().size() > 1); DeclGroupRef::iterator I = DGR.begin(); DeclGroupRef::iterator E = DGR.end(); --E; Decl *FirstD = (*I); VarDecl *FirstVD = dyn_cast(FirstD); Decl *LastD = (*E); VarDecl *LastVD = dyn_cast(LastD); TransAssert(FirstVD && "Bad First VarDecl!"); TransAssert(LastVD && "Bad First VarDecl!"); SourceLocation TypeLocEnd = getVarDeclTypeLocEnd(FirstVD); SourceRange LastVarRange = LastVD->getSourceRange(); SourceLocation LastEndLoc = getEndLocationUntil(LastVarRange, ';'); getStringBetweenLocs(Str, TypeLocEnd, LastEndLoc); SourceLocation StartLoc = FirstVD->getBeginLoc(); SourceLocation NewLastEndLoc = getLocationAfterSkiping(LastEndLoc, ';'); return !(TheRewriter->RemoveText(SourceRange(StartLoc, NewLastEndLoc))); } SourceLocation RewriteUtils::getDeclGroupRefEndLoc(DeclGroupRef DGR) { Decl *LastD; if (DGR.isSingleDecl()) { LastD = DGR.getSingleDecl(); } else { DeclGroupRef::iterator E = DGR.end(); --E; LastD = (*E); } #if 0 VarDecl *VD = dyn_cast(LastD); TransAssert(VD && "Bad VD!"); SourceRange VarRange = VD->getSourceRange(); return getEndLocationFromBegin(VarRange); #endif // The LastD could be a RecordDecl SourceRange Range = LastD->getSourceRange(); SourceLocation EndLoc = getEndLocationFromBegin(Range); TransAssert(EndLoc.isValid() && "Invalid EndLoc!"); return EndLoc; } SourceLocation RewriteUtils::getDeclStmtEndLoc(DeclStmt *DS) { DeclGroupRef DGR = DS->getDeclGroup(); return getDeclGroupRefEndLoc(DGR); } bool RewriteUtils::getDeclStmtStrAndRemove(DeclStmt *DS, std::string &Str) { DeclGroupRef DGR = DS->getDeclGroup(); return getDeclGroupStrAndRemove(DGR, Str); } bool RewriteUtils::removeAStarBefore(const Decl *D) { SourceLocation LocStart = D->getLocation(); const char *StartBuf = SrcManager->getCharacterData(LocStart); int Offset = 0; while (*StartBuf != '*') { StartBuf--; Offset--; } SourceLocation StarLoc = LocStart.getLocWithOffset(Offset); return !TheRewriter->RemoveText(StarLoc, 1); } bool RewriteUtils::removeASymbolAfter(const Expr *E, char Symbol) { SourceRange ExprRange = E->getSourceRange(); SourceLocation LocStart = ExprRange.getBegin(); const char *StartBuf = SrcManager->getCharacterData(LocStart); int Offset = 0; while (*StartBuf != Symbol) { StartBuf++; Offset++; } SourceLocation StarLoc = LocStart.getLocWithOffset(Offset); return !TheRewriter->RemoveText(StarLoc, 1); } bool RewriteUtils::removeAStarAfter(const Expr *E) { return removeASymbolAfter(E, '*'); } bool RewriteUtils::removeAnAddrOfAfter(const Expr *E) { return removeASymbolAfter(E, '&'); } bool RewriteUtils::insertAnAddrOfBefore(const Expr *E) { SourceRange ExprRange = E->getSourceRange(); SourceLocation LocStart = ExprRange.getBegin(); return !TheRewriter->InsertTextBefore(LocStart, "&"); } bool RewriteUtils::insertAStarBefore(const Expr *E) { SourceRange ExprRange = E->getSourceRange(); SourceLocation LocStart = ExprRange.getBegin(); return !TheRewriter->InsertTextBefore(LocStart, "*"); } bool RewriteUtils::removeVarInitExpr(const VarDecl *VD) { TransAssert(VD->hasInit() && "VarDecl doesn't have an Init Expr!"); SourceLocation NameStartLoc = VD->getLocation(); SourceLocation InitStartLoc = getLocationUntil(NameStartLoc, '='); const Expr *Init = VD->getInit(); SourceRange ExprRange = Init->getSourceRange(); SourceLocation InitEndLoc = ExprRange.getEnd(); // handle macro, e.g.: // #define NULL 0 // void foo(void) // { // int *p = NULL; // } if (SrcManager->isMacroBodyExpansion(InitEndLoc)) { InitEndLoc = SrcManager->getFileLoc(InitEndLoc); } return !TheRewriter->RemoveText(SourceRange(InitStartLoc, InitEndLoc)); } SourceLocation RewriteUtils::getMacroExpansionLoc(SourceLocation Loc) { if (SrcManager->isMacroBodyExpansion(Loc)) return SrcManager->getFileLoc(Loc); return Loc; } bool RewriteUtils::removeVarDecl(const VarDecl *VD, DeclGroupRef DGR) { SourceRange VarRange = VD->getSourceRange(); if (DGR.isSingleDecl()) { SourceLocation StartLoc = getMacroExpansionLoc(VarRange.getBegin()); SourceLocation EndLoc = getEndLocationUntil(VarRange, ';'); // in case the previous EndLoc is invalid, for example, // VarRange could have bad EndLoc value if (EndLoc.isInvalid()) EndLoc = getLocationUntil(StartLoc, ';'); return !(TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc))); } DeclGroupRef::const_iterator I = DGR.begin(); const VarDecl *FirstVD = dyn_cast(*I); // dyn_cast (*I) to VarDecl could fail, because it could be a struct decl, // e.g., struct S1 { int f1; } s2 = {1}, where FirstDecl is // struct S1 {int f1;}. We need to skip it if (!FirstVD) { // handle the case where we could have implicit declaration of RecordDecl // e.g., // struct S0 *s; // ...; // in this case, struct S0 is implicitly declared if ( RecordDecl *RD = dyn_cast(*I) ) { if (!RD->getDefinition() && DGR.getDeclGroup().size() == 2) { SourceLocation StartLoc = VarRange.getBegin(); SourceLocation EndLoc = getEndLocationUntil(VarRange, ';'); return !(TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc))); } } ++I; TransAssert((I != DGR.end()) && "Bad Decl!"); FirstVD = dyn_cast(*I); TransAssert(FirstVD && "Invalid Var Decl!"); if (VD == FirstVD) { SourceLocation StartLoc = VD->getLocation(); SourceLocation EndLoc; if (I + 1 == DGR.end()) { EndLoc = StartLoc; } else { EndLoc = getEndLocationUntil(VarRange, ','); } return !(TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc))); } } else if (VD == FirstVD) { SourceLocation StartLoc = getVarDeclTypeLocEnd(VD); SourceLocation EndLoc = getEndLocationUntil(VarRange, ','); return !(TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc))); } const Decl *PrevDecl = FirstVD; const VarDecl *CurrVD = NULL; ++I; DeclGroupRef::const_iterator E = DGR.end(); for (; I != E; ++I) { CurrVD = dyn_cast(*I); if (CurrVD && VD == CurrVD) break; PrevDecl = *I; } TransAssert((VD == CurrVD) && "Cannot find VD!"); SourceLocation VarEndLoc = VarRange.getEnd(); SourceRange PrevDeclRange = PrevDecl->getSourceRange(); SourceLocation PrevDeclEndLoc = getEndLocationUntil(PrevDeclRange, ','); return !(TheRewriter->RemoveText(SourceRange(PrevDeclEndLoc, VarEndLoc))); } void RewriteUtils::getTmpTransName(unsigned Postfix, std::string &Name) { std::stringstream SS; SS << getTmpVarNamePrefix() << Postfix; Name = SS.str(); } bool RewriteUtils::insertStringBeforeFunc(const FunctionDecl *FD, const std::string &Str) { SourceRange FuncRange; if (FunctionTemplateDecl *TmplD = FD->getDescribedFunctionTemplate()) { FuncRange = TmplD->getSourceRange(); } else { FuncRange = FD->getSourceRange(); } SourceLocation StartLoc = FuncRange.getBegin(); return !TheRewriter->InsertTextBefore(StartLoc, Str); } bool RewriteUtils::insertStringBeforeTemplateDecl(const TemplateDecl *D, const std::string &Str) { SourceRange Range = D->getSourceRange(); SourceLocation StartLoc = Range.getBegin(); TransAssert(StartLoc.isValid() && "Invalid template decl StartLoc!"); return !TheRewriter->InsertTextBefore(StartLoc, Str); } bool RewriteUtils::replaceUnionWithStruct(const NamedDecl *ND) { SourceRange NDRange = ND->getSourceRange(); int RangeSize = TheRewriter->getRangeSize(NDRange); TransAssert((RangeSize != -1) && "Bad Range!"); SourceLocation StartLoc = NDRange.getBegin(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::string TmpStr(StartBuf, RangeSize); std::string UStr = "union"; size_t Pos = TmpStr.find(UStr); if (Pos == std::string::npos) return true; if (Pos != 0) StartLoc = StartLoc.getLocWithOffset(Pos); return !TheRewriter->ReplaceText(StartLoc, UStr.size(), "struct"); } bool RewriteUtils::removeIfAndCond(const IfStmt *IS) { SourceLocation IfLoc = IS->getIfLoc(); const Stmt *ThenStmt = IS->getThen(); TransAssert(ThenStmt && "NULL ThenStmt!"); SourceLocation ThenLoc = getRealLocation(ThenStmt->getBeginLoc()); SourceLocation EndLoc = ThenLoc.getLocWithOffset(-1); Rewriter::RewriteOptions Opts; // We don't want to include the previously inserted string Opts.IncludeInsertsAtBeginOfRange = false; return !TheRewriter->RemoveText(SourceRange(getRealLocation(IfLoc), EndLoc), Opts); } bool RewriteUtils::removeArraySubscriptExpr(const Expr *E) { SourceRange ERange = E->getSourceRange(); SourceLocation StartLoc = ERange.getBegin(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); int Offset = 0; while (*StartBuf != '[') { StartBuf--; Offset--; } StartLoc = StartLoc.getLocWithOffset(Offset); SourceLocation EndLoc = ERange.getEnd(); EndLoc = EndLoc.getLocWithOffset(1); if (EndLoc.isInvalid()) return !TheRewriter->RemoveText(SourceRange(StartLoc, ERange.getEnd())); SourceLocation RBLoc = getLocationUntil(EndLoc, ']'); if (RBLoc.isInvalid()) return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); return !TheRewriter->RemoveText(SourceRange(StartLoc, RBLoc)); } bool RewriteUtils::getFunctionDefStrAndRemove(const FunctionDecl *FD, std::string &Str) { SourceRange FDRange = FD->getSourceRange(); int RangeSize = TheRewriter->getRangeSize(FDRange); if (RangeSize == -1) return false; SourceLocation StartLoc = FDRange.getBegin(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); Str.assign(StartBuf, RangeSize); TheRewriter->RemoveText(FDRange); return true; } bool RewriteUtils::getFunctionDeclStrAndRemove(const FunctionDecl *FD, std::string &Str) { TransAssert(!FD->isThisDeclarationADefinition() && "FD cannot be a definition!"); SourceRange FDRange = FD->getSourceRange(); SourceLocation StartLoc = FDRange.getBegin(); SourceLocation EndLoc = getEndLocationUntil(FDRange, ';'); getStringBetweenLocs(Str, StartLoc, EndLoc); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); } bool RewriteUtils::replaceFunctionDefWithStr(const FunctionDecl *FD, const std::string &Str) { const Stmt *Body = FD->getBody(); TransAssert(Body && "FunctionDecl is not a definition!"); SourceRange Range = Body->getSourceRange(); SourceLocation StartLoc = Range.getBegin(); if (StartLoc.isMacroID()) StartLoc = SrcManager->getExpansionLoc(StartLoc); SourceLocation EndLoc = Range.getEnd(); if (EndLoc.isMacroID()) EndLoc = SrcManager->getExpansionLoc(EndLoc); return !TheRewriter->ReplaceText(SourceRange(StartLoc, EndLoc), Str); } // FIXME: probably we don't need this function, because we could use // removeDecl insteadly bool RewriteUtils::removeFieldDecl(const FieldDecl *FD) { SourceRange Range = FD->getSourceRange(); SourceLocation StartLoc = Range.getBegin(); SourceLocation EndLoc = getEndLocationUntil(Range, ';'); SourceLocation CurlyEndLoc = getEndLocationUntil(Range, '}'); // handle cases like: // struct { // int f <- no semicolon here // }; const char *SemiPos = SrcManager->getCharacterData(EndLoc); const char *CurlyPos = SrcManager->getCharacterData(CurlyEndLoc); if (SemiPos > CurlyPos) { EndLoc = CurlyEndLoc.getLocWithOffset(-1); } // If EndLoc is invalid, just remove one char to avoid crash if (EndLoc.isInvalid()) { EndLoc = StartLoc; } return !(TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc))); } bool RewriteUtils::removeDecl(const Decl *D) { SourceRange Range = D->getSourceRange(); TransAssert((TheRewriter->getRangeSize(Range) != -1) && "Bad UsingDecl SourceRange!"); SourceLocation StartLoc = Range.getBegin(); SourceLocation EndLoc = getEndLocationUntil(Range, ';'); return !(TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc))); } bool RewriteUtils::replaceCXXDtorCallExpr(const CXXMemberCallExpr *CE, std::string &Name) { const CXXMethodDecl *MD = CE->getMethodDecl(); const CXXDestructorDecl *DtorDecl = dyn_cast(MD); if (!DtorDecl) return true; Name = "~" + Name; std::string ExprStr; getExprString(CE, ExprStr); std::string OldDtorName = DtorDecl->getNameAsString(); size_t Pos = ExprStr.find(OldDtorName); TransAssert((Pos != std::string::npos) && "Bad Name Position!"); if (Pos == 0) return true; SourceLocation StartLoc = CE->getBeginLoc(); StartLoc = StartLoc.getLocWithOffset(Pos); return !(TheRewriter->ReplaceText(StartLoc, OldDtorName.size(), Name)); } SourceRange RewriteUtils::getFileLocSourceRange(SourceRange LocRange) { SourceLocation StartLoc = LocRange.getBegin(); if (StartLoc.isMacroID()) { StartLoc = SrcManager->getSpellingLoc(StartLoc); SourceLocation EndLoc = LocRange.getEnd(); TransAssert(EndLoc.isMacroID() && "EndLoc is not from a macro!"); LocRange = SourceRange(StartLoc, SrcManager->getSpellingLoc(EndLoc)); } return LocRange; } bool RewriteUtils::removeSpecifier(NestedNameSpecifierLoc Loc) { SourceRange LocRange = getFileLocSourceRange(Loc.getLocalSourceRange()); TransAssert((TheRewriter->getRangeSize(LocRange) != -1) && "Bad NestedNameSpecifierLoc Range!"); return !(TheRewriter->RemoveText(LocRange)); } bool RewriteUtils::replaceSpecifier(NestedNameSpecifierLoc Loc, const std::string &Name) { SourceRange LocRange = getFileLocSourceRange(Loc.getLocalSourceRange()); TransAssert((TheRewriter->getRangeSize(LocRange) != -1) && "Bad NestedNameSpecifierLoc Range!"); return !(TheRewriter->ReplaceText(LocRange, Name + "::")); } void RewriteUtils::getQualifierAsString(NestedNameSpecifierLoc Loc, std::string &Str) { SourceLocation StartLoc = Loc.getBeginLoc(); TransAssert(StartLoc.isValid() && "Bad StartLoc for NestedNameSpecifier!"); SourceRange Range = Loc.getSourceRange(); int Len = TheRewriter->getRangeSize(Range); const char *StartBuf = SrcManager->getCharacterData(StartLoc); Str.assign(StartBuf, Len); } void RewriteUtils::getSpecifierAsString(NestedNameSpecifierLoc Loc, std::string &Str) { SourceLocation StartLoc = Loc.getBeginLoc(); TransAssert(StartLoc.isValid() && "Bad StartLoc for NestedNameSpecifier!"); const char *StartBuf = SrcManager->getCharacterData(StartLoc); const char *OrigBuf = StartBuf; unsigned int Len = 0; while (!isspace(*StartBuf) && (*StartBuf != ':')) { StartBuf++; Len++; } Str.assign(OrigBuf, Len); } bool RewriteUtils::replaceRecordType(RecordTypeLoc &RTLoc, const std::string &Name) { const IdentifierInfo *TypeId = RTLoc.getType().getBaseTypeIdentifier(); if (!TypeId) return true; SourceLocation LocStart = RTLoc.getBeginLoc(); // Loc could be invalid, for example: // class AAA { }; // class BBB:AAA { // public: // BBB () { } // }; // In Clang's internal representation, BBB's Ctor is BBB() : AAA() {} // The implicit AAA() will be visited here // This is the only case where RTLoc is invalid, so the question is - // Is the guard below too strong? It is possible it could mask other // potential bugs? if (LocStart.isInvalid()) return true; return !(TheRewriter->ReplaceText(LocStart, TypeId->getLength(), Name)); } bool RewriteUtils::isTheFirstDecl(const VarDecl *VD) { SourceRange Range = VD->getSourceRange(); SourceLocation StartLoc = Range.getBegin(); SourceLocation NameStartLoc = VD->getLocation(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); const char *NameStartBuf = SrcManager->getCharacterData(NameStartLoc); while (StartBuf != NameStartBuf) { if (*StartBuf == ',') return false; StartBuf++; } return true; } bool RewriteUtils::isSingleDecl(const VarDecl *VD) { if (!isTheFirstDecl(VD)) return false; SourceRange Range = VD->getSourceRange(); SourceLocation StartLoc = Range.getBegin(); int RangeSize = TheRewriter->getRangeSize(Range); SourceLocation EndLoc = StartLoc.getLocWithOffset(RangeSize); const char *EndBuf = SrcManager->getCharacterData(EndLoc); while (isspace(*EndBuf)) EndBuf++; return (*EndBuf == ';'); } // In case we don't know if VD is in a single decl group, // also we don't know if VD is the first decl or not. // once this version is well-tested, probably we should remove // bool RewriteUtils::removeVarDecl(const VarDecl *VD, // DeclGroupRef DGR) bool RewriteUtils::removeVarDecl(const VarDecl *VD) { if (isSingleDecl(VD)) { return removeDecl(VD); } SourceRange VarRange = VD->getSourceRange(); // VD is the first declaration in a declaration group. // We keep the leading type string if (isTheFirstDecl(VD)) { // We need to get the outermost TypeLocEnd instead of the StartLoc of // a var name, because we need to handle the case below: // int *x, *y; // If we rely on the StartLoc of a var name, then we will make bad // transformation like: // int * *y; SourceLocation NewStartLoc = getVarDeclTypeLocEnd(VD); SourceLocation NewEndLoc = getEndLocationUntil(VarRange, ','); return !(TheRewriter->RemoveText(SourceRange(NewStartLoc, NewEndLoc))); } SourceLocation NameLoc = VD->getLocation(); SourceLocation VarStartLoc = VarRange.getBegin(); const char *NameStartBuf = SrcManager->getCharacterData(NameLoc); const char *VarStartBuf = SrcManager->getCharacterData(VarStartLoc); int Offset = 0; TransAssert((VarStartBuf < NameStartBuf) && "Bad Name Location!"); while (NameStartBuf != VarStartBuf) { if (*NameStartBuf == ',') break; Offset--; NameStartBuf--; } TransAssert((VarStartBuf < NameStartBuf) && "Cannot find comma!"); SourceLocation PrevDeclEndLoc = NameLoc.getLocWithOffset(Offset); SourceLocation VarEndLoc = VarRange.getEnd(); return !(TheRewriter->RemoveText(SourceRange(PrevDeclEndLoc, VarEndLoc))); } bool RewriteUtils::removeTextFromLeftAt(SourceRange Range, char C, SourceLocation EndLoc) { SourceLocation StartLoc = Range.getBegin(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); int Offset = 0; while (*StartBuf != C) { StartBuf--; Offset--; } StartLoc = StartLoc.getLocWithOffset(Offset); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); } SourceLocation RewriteUtils::getLocationFromLeftUntil(SourceLocation StartLoc, char C) { const char *StartBuf = SrcManager->getCharacterData(StartLoc); int Offset = 0; while (*StartBuf != C) { StartBuf--; Offset--; } return StartLoc.getLocWithOffset(Offset); } bool RewriteUtils::removeTextUntil(SourceRange Range, char C) { SourceLocation StartLoc = Range.getBegin(); // I don't know the reason, but seems Clang treats the following two // cases differently: // (1) template // in this case, the RangeSize is 5, which includes the ',' // (2) template // in this case, the RangeSize is 8, which excludes the comma SourceLocation EndLoc = Range.getEnd(); const char *EndBuf = SrcManager->getCharacterData(EndLoc); if (*EndBuf != C) EndLoc = getEndLocationUntil(Range, C); return !TheRewriter->RemoveText(SourceRange(StartLoc, EndLoc)); } bool RewriteUtils::removeCXXCtorInitializer(const CXXCtorInitializer *Init, unsigned Index, unsigned NumInits) { SourceRange Range = Init->getSourceRange(); SourceLocation EndLoc = Init->getRParenLoc(); if (Index == 0) { if (NumInits == 1) return removeTextFromLeftAt(Range, ':', EndLoc); else return removeTextUntil(Range, ','); } else { return removeTextFromLeftAt(Range, ',', EndLoc); } } bool RewriteUtils::removeClassDecls(const CXXRecordDecl *CXXRD) { for (CXXRecordDecl::redecl_iterator I = CXXRD->redecls_begin(), E = CXXRD->redecls_end(); I != E; ++I) { SourceRange Range = (*I)->getSourceRange(); SourceLocation LocEnd; if ((*I)->isThisDeclarationADefinition()) { LocEnd = (*I)->getBraceRange().getEnd(); if (LocEnd.isValid()) LocEnd = getLocationUntil(LocEnd, ';'); else LocEnd = getEndLocationUntil(Range, ';'); } else { LocEnd = getEndLocationUntil(Range, ';'); } TheRewriter->RemoveText(SourceRange(Range.getBegin(), LocEnd)); } return true; } bool RewriteUtils::removeClassTemplateDecls(const ClassTemplateDecl *TmplD) { for (ClassTemplateDecl::redecl_iterator I = TmplD->redecls_begin(), E = TmplD->redecls_end(); I != E; ++I) { const CXXRecordDecl *CXXRD = dyn_cast((*I)->getTemplatedDecl()); TransAssert(CXXRD && "Invalid class template!"); SourceRange Range = (*I)->getSourceRange(); SourceLocation LocEnd; if (CXXRD->isThisDeclarationADefinition()) { LocEnd = CXXRD->getBraceRange().getEnd(); LocEnd = getLocationUntil(LocEnd, ';'); } else { LocEnd = getEndLocationUntil(Range, ';'); } TheRewriter->RemoveText(SourceRange(Range.getBegin(), LocEnd)); } return true; } bool RewriteUtils::replaceCXXMethodNameAfterQualifier( const NestedNameSpecifierLoc *QualLoc, const CXXMethodDecl *MD, const std::string &NewName) { SourceLocation EndLoc = QualLoc->getEndLoc(); const char *EndBuf = SrcManager->getCharacterData(EndLoc); unsigned int Offset = 0; while (isspace(*EndBuf) || (*EndBuf == ':')) { EndBuf++; Offset++; } EndLoc = EndLoc.getLocWithOffset(Offset); TheRewriter->ReplaceText(EndLoc, MD->getNameAsString().size(), NewName); return true; } cvise-2.3.0/clang_delta/RewriteUtils.h000066400000000000000000000275171402162750500177130ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef REWRITE_UTILS_H #define REWRITE_UTILS_H #include #include "clang/Basic/SourceLocation.h" #include "clang/AST/NestedNameSpecifier.h" #ifndef ENABLE_TRANS_ASSERT #define TransAssert(x) {if (!(x)) exit(-1);} #else #define TransAssert(x) assert(x) #endif namespace clang { class ParmVarDecl; class VarDecl; class Decl; class DeclStmt; class Rewriter; class SourceManager; class CallExpr; class Expr; class FunctionDecl; class TemplateDecl; class Stmt; class DeclGroupRef; class DeclRefExpr; class NamedDecl; class IfStmt; class Type; class FieldDecl; class CXXConstructExpr; class RecordDecl; class CXXMemberCallExpr; class RecordTypeLoc; class CXXDestructorDecl; class CXXCtorInitializer; class CXXRecordDecl; class ClassTemplateDecl; class CXXMethodDecl; class NestedNameSpecifierLoc; class ValueDecl; } class RewriteUtils { public: static RewriteUtils *GetInstance(clang::Rewriter *RW); static void Finalize(void); clang::SourceLocation getEndLocationFromBegin(clang::SourceRange Range); bool removeParamFromFuncDecl(const clang::ParmVarDecl *PV, unsigned int NumParams, int ParamPos); bool removeArgFromCallExpr(const clang::CallExpr *CallE, int ParamPos); bool removeArgFromCXXConstructExpr(const clang::CXXConstructExpr *CE, int ParamPos); bool removeVarFromDeclStmt(clang::DeclStmt *DS, const clang::VarDecl *VD, clang::Decl *PrevDecl, bool IsFirstDecl, bool *StmtRemoved); bool getExprString(const clang::Expr *E, std::string &ES); bool getStmtString(const clang::Stmt *S, std::string &Str); bool replaceExpr(const clang::Expr *E, const std::string &ES); bool replaceExprNotInclude(const clang::Expr *E, const std::string &ES); bool addLocalVarToFunc(const std::string &VarStr, clang::FunctionDecl *FD); std::string getStmtIndentString(clang::Stmt *S, clang::SourceManager *SrcManager); bool addNewAssignStmtBefore(clang::Stmt *BeforeStmt, const std::string &VarName, clang::Expr *RHS, bool NeedParen); bool addStringBeforeStmt(clang::Stmt *BeforeStmt, const std::string &Str, bool NeedParen); bool addStringBeforeStmtAndReplaceExpr(clang::Stmt *BeforeStmt, const std::string &StmtStr, const clang::Expr *E, const std::string &ExprStr, bool NeedParen); bool addStringAfterStmt(clang::Stmt *AfterStmt, const std::string &Str); bool addStringAfterVarDecl(const clang::VarDecl *VD, const std::string &Str); bool addStringAfterFuncDecl(const clang::FunctionDecl *FD, const std::string &Str); bool replaceVarDeclName(clang::VarDecl *VD, const std::string &NameStr); bool replaceFunctionDeclName(const clang::FunctionDecl *FD, const std::string &NameStr); bool replaceRecordDeclName(const clang::RecordDecl *RD, const std::string &NameStr); bool replaceRecordDeclDef(const clang::RecordDecl *RD, const std::string &NameStr); bool replaceVarTypeName(const clang::VarDecl *VD, const std::string &NameStr); const char *getTmpVarNamePrefix(void); void getStringBetweenLocs(std::string &Str, clang::SourceLocation LocStart, clang::SourceLocation LocEnd); void getStringBetweenLocsAfterStart(std::string &Str, clang::SourceLocation LocStart, clang::SourceLocation LocEnd); bool getDeclGroupStrAndRemove(clang::DeclGroupRef DGR, std::string &Str); bool getEntireDeclGroupStrAndRemove(clang::DeclGroupRef DGR, std::string &Str); clang::SourceLocation getDeclGroupRefEndLoc(clang::DeclGroupRef DGR); bool getDeclStmtStrAndRemove(clang::DeclStmt *DS, std::string &Str); clang::SourceLocation getDeclStmtEndLoc(clang::DeclStmt *DS); bool removeAStarBefore(const clang::Decl *D); bool removeAStarAfter(const clang::Expr *E); bool removeAnAddrOfAfter(const clang::Expr *E); bool removeASymbolAfter(const clang::Expr *E, char Symbol); bool insertAnAddrOfBefore(const clang::Expr *E); bool insertAStarBefore(const clang::Expr *E); bool removeVarInitExpr(const clang::VarDecl *VD); bool removeVarDecl(const clang::VarDecl *VD, clang::DeclGroupRef DGR); bool removeVarDecl(const clang::VarDecl *VD); void getTmpTransName(unsigned Postfix, std::string &Name); bool insertStringBeforeFunc(const clang::FunctionDecl *FD, const std::string &Str); bool insertStringBeforeTemplateDecl(const clang::TemplateDecl *D, const std::string &Str); bool replaceUnionWithStruct(const clang::NamedDecl *ND); bool removeIfAndCond(const clang::IfStmt *IS); clang::SourceLocation getLocationUntil(clang::SourceLocation Loc, char Symbol); clang::SourceLocation getLocationAfter(clang::SourceLocation Loc, char Symbol); bool removeArraySubscriptExpr(const clang::Expr *E); bool getFunctionDefStrAndRemove(const clang::FunctionDecl *FD, std::string &Str); bool getFunctionDeclStrAndRemove(const clang::FunctionDecl *FD, std::string &Str); bool replaceFunctionDefWithStr(const clang::FunctionDecl *FD, const std::string &Str); clang::SourceLocation getEndLocationUntil(clang::SourceRange Range, char Symbol); bool removeFieldDecl(const clang::FieldDecl *FD); bool removeDecl(const clang::Decl *D); bool replaceNamedDeclName(const clang::NamedDecl *ND, const std::string &NameStr); ///\brief Replaces a value decl with a given string. /// ///For example: \code /// enum E {...}; /// template struct S { } => template struct S { } ///\endcode /// ///\param[in] VD - The decl to be replaced. ///\param[in] Str - The replacement ///\returns true on success. /// bool replaceValueDecl(const clang::ValueDecl *ValD, const std::string &Str); bool replaceCXXDtorCallExpr(const clang::CXXMemberCallExpr *CE, std::string &Name); bool removeSpecifier(clang::NestedNameSpecifierLoc Loc); bool replaceSpecifier(clang::NestedNameSpecifierLoc Loc, const std::string &Name); void getQualifierAsString(clang::NestedNameSpecifierLoc Loc, std::string &Str); void getSpecifierAsString(clang::NestedNameSpecifierLoc Loc, std::string &Str); bool replaceRecordType(clang::RecordTypeLoc &RTLoc, const std::string &Name); bool isSingleDecl(const clang::VarDecl *VD); bool isTheFirstDecl(const clang::VarDecl *VD); bool removeTextFromLeftAt(clang::SourceRange Range, char C, clang::SourceLocation EndLoc); clang::SourceLocation getLocationFromLeftUntil(clang::SourceLocation StartLoc, char C); bool removeTextUntil(clang::SourceRange Range, char C); bool replaceCXXDestructorDeclName(const clang::CXXDestructorDecl *DtorDecl, const std::string &Name); bool removeCXXCtorInitializer(const clang::CXXCtorInitializer *Init, unsigned Index, unsigned NumInits); bool removeClassDecls(const clang::CXXRecordDecl *CXXRD); bool removeClassTemplateDecls(const clang::ClassTemplateDecl *TmplD); bool replaceCXXMethodNameAfterQualifier( const clang::NestedNameSpecifierLoc *QualLoc, const clang::CXXMethodDecl *MD, const std::string &NewName); clang::SourceLocation getRealLocation(clang::SourceLocation Loc); clang::SourceRange getRealSourceRange(clang::SourceRange Range); clang::SourceLocation getLocationAfterSkiping(clang::SourceLocation StartLoc, char Symbol); private: static RewriteUtils *Instance; static const char *TmpVarNamePrefix; clang::Rewriter *TheRewriter; clang::SourceManager *SrcManager; RewriteUtils(void) : TheRewriter(NULL), SrcManager(NULL) { } ~RewriteUtils(void) { } int getOffsetUntil(const char *Buf, char Symbol); int getSkippingOffset(const char *Buf, char Symbol); clang::SourceLocation getEndLocationAfter(clang::SourceRange Range, char Symbol); unsigned getLocationOffsetAndFileID(clang::SourceLocation Loc, clang::FileID &FID, clang::SourceManager *SrcManager); clang::SourceLocation getVarDeclTypeLocEnd(const clang::VarDecl *VD); clang::SourceLocation getVarDeclTypeLocBegin(const clang::VarDecl *VD); clang::SourceLocation getParamSubstringLocation(clang::SourceLocation StartLoc, size_t Size, const std::string &Substr); void indentAfterNewLine(llvm::StringRef Str, std::string &NewStr, const std::string &IndentStr); void addOpenParenBeforeStmt(clang::Stmt *S, const std::string &IndentStr); bool addStringBeforeStmtInternal(clang::Stmt *S, const std::string &Str, const std::string &IndentStr, bool NeedParen); unsigned getOffsetBetweenLocations(clang::SourceLocation StartLoc, clang::SourceLocation EndLoc, clang::SourceManager *SrcManager); clang::SourceLocation skipPossibleTypeRange(const clang::Type *Ty, clang::SourceLocation OrigEndLoc, clang::SourceLocation VarStartLoc); void skipRangeByType(const std::string &BufStr, const clang::Type *Ty, int &Offset); bool removeArgFromExpr(const clang::Expr *E, int ParamPos); const clang::Expr *getArgWrapper(const clang::Expr *E, int ParamPos); unsigned getNumArgsWrapper(const clang::Expr *E); clang::SourceLocation getExpansionEndLoc(clang::SourceLocation EndLoc); clang::SourceLocation getMacroExpansionLoc(clang::SourceLocation Loc); clang::SourceRange getFileLocSourceRange(clang::SourceRange LocRange); // Unimplemented RewriteUtils(const RewriteUtils &); void operator=(const RewriteUtils &); }; #endif cvise-2.3.0/clang_delta/SimpleInliner.cpp000066400000000000000000000412501402162750500203440ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimpleInliner.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonStatementVisitor.h" using namespace clang; static const char *DescriptionMsg = "A really simple inliner. \ This transformation does a simple source-to-source \ inlining. To avoid the abuse of inlining, I put \ some constraints on the size of a function which \ can be inlined - if a function has less than 10 statements, \ then it's legitimate. \n\ \n\ Steps of inlining: \n\ * create a tmp var for function return value; \n\ * create a new block which is a copy of the inlined function; \n\ * at the top of this newly block, inlined function's parameters \ will be declared as local vars with callexpr's arguments as their \ initialization values (if any) \n\ * inside this newly block, replace all return statements as \ assignment statements, where the LHS is the created tmp var \ (Note that if the inlined function returns void, then \ this step is skipped) \n\ * replace the callexpr with tmp var above \n\ \n\ Each transformation iteration only transforms one callexpr, \ also it will keep the inlined function body unchanged. \ If the inlined body has no reference anymore, c_delta \ will remove it entirely. \n"; static RegisterTransformation Trans("simple-inliner", DescriptionMsg); class SimpleInlinerCollectionVisitor : public RecursiveASTVisitor { public: explicit SimpleInlinerCollectionVisitor(SimpleInliner *Instance) : ConsumerInstance(Instance), NumStmts(0) { } bool VisitStmt(Stmt *S); bool VisitCallExpr(CallExpr *CE); bool TraverseConstructorInitializer(CXXCtorInitializer *Init); bool TraverseParmVarDecl(ParmVarDecl *PV); unsigned int getNumStmts(void) { return NumStmts; } void setNumStmts(unsigned int Num) { NumStmts = Num; } private: SimpleInliner *ConsumerInstance; unsigned int NumStmts; }; class SimpleInlinerFunctionVisitor : public RecursiveASTVisitor { public: explicit SimpleInlinerFunctionVisitor(SimpleInliner *Instance) : ConsumerInstance(Instance) { } bool VisitReturnStmt(ReturnStmt *RS); bool VisitDeclRefExpr(DeclRefExpr *DRE); private: SimpleInliner *ConsumerInstance; }; class SimpleInlinerFunctionStmtVisitor : public RecursiveASTVisitor { public: explicit SimpleInlinerFunctionStmtVisitor(SimpleInliner *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: SimpleInliner *ConsumerInstance; }; class SimpleInlinerStmtVisitor : public CommonStatementVisitor { public: explicit SimpleInlinerStmtVisitor(SimpleInliner *Instance) : ConsumerInstance(Instance) { } bool VisitCallExpr(CallExpr *CallE); private: SimpleInliner *ConsumerInstance; }; bool SimpleInlinerCollectionVisitor::VisitStmt(Stmt *S) { Stmt::StmtClass SC = S->getStmtClass(); switch (SC) { case Stmt::BreakStmtClass: case Stmt::CompoundStmtClass: case Stmt::ContinueStmtClass: case Stmt::DeclStmtClass: case Stmt::DoStmtClass: case Stmt::ForStmtClass: case Stmt::GotoStmtClass: case Stmt::IndirectGotoStmtClass: case Stmt::IfStmtClass: case Stmt::ReturnStmtClass: case Stmt::CaseStmtClass: case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: case Stmt::BinaryOperatorClass: NumStmts++; break; default: break; } return true; } bool SimpleInlinerCollectionVisitor::VisitCallExpr(CallExpr *CE) { FunctionDecl *FD = CE->getDirectCallee(); if (!FD) return true; ConsumerInstance->AllCallExprs.push_back(CE); ConsumerInstance->CalleeToCallerMap[CE] = ConsumerInstance->CurrentFD; FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); unsigned int NumCalls = ConsumerInstance->FunctionDeclNumCalls[CanonicalFD]; NumCalls++; ConsumerInstance->FunctionDeclNumCalls[CanonicalFD] = NumCalls; NumStmts++; return true; } // Overload the default traverse function, because we cannot inline // Ctor's initializer bool SimpleInlinerCollectionVisitor::TraverseConstructorInitializer( CXXCtorInitializer *Init) { return true; } bool SimpleInlinerCollectionVisitor::TraverseParmVarDecl(ParmVarDecl *PV) { return true; } bool SimpleInlinerFunctionVisitor::VisitReturnStmt(ReturnStmt *RS) { ConsumerInstance->ReturnStmts.push_back(RS); return true; } bool SimpleInlinerFunctionVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { const ValueDecl *OrigDecl = DRE->getDecl(); const ParmVarDecl *PD = dyn_cast(OrigDecl); if (PD) ConsumerInstance->ParmRefs.push_back(DRE); return true; } bool SimpleInlinerFunctionStmtVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || !FD->isThisDeclarationADefinition()) return true; if (FD->getBeginLoc().isInvalid() || FD->getEndLoc().isInvalid()) return true; ConsumerInstance->CurrentFD = FD; ConsumerInstance->CollectionVisitor->setNumStmts(0); ConsumerInstance->CollectionVisitor->TraverseDecl(FD); if (!FD->isVariadic()) { ConsumerInstance->FunctionDeclNumStmts[FD->getCanonicalDecl()] = ConsumerInstance->CollectionVisitor->getNumStmts(); } return true; } bool SimpleInlinerStmtVisitor::VisitCallExpr(CallExpr *CallE) { if (ConsumerInstance->TheCallExpr == CallE) { ConsumerInstance->TheStmt = CurrentStmt; ConsumerInstance->NeedParen = NeedParen; // Stop recursion return false; } return true; } void SimpleInliner::Initialize(ASTContext &context) { Transformation::Initialize(context); NameQueryWrap = new TransNameQueryWrap(RewriteHelper->getTmpVarNamePrefix()); CollectionVisitor = new SimpleInlinerCollectionVisitor(this); FunctionVisitor = new SimpleInlinerFunctionVisitor(this); FunctionStmtVisitor = new SimpleInlinerFunctionStmtVisitor(this); StmtVisitor = new SimpleInlinerStmtVisitor(this); } bool SimpleInliner::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { FunctionStmtVisitor->TraverseDecl(*I); } return true; } void SimpleInliner::HandleTranslationUnit(ASTContext &Ctx) { doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(CurrentFD && "NULL CurrentFD!"); TransAssert(TheCallExpr && "NULL TheCallExpr!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); NameQueryWrap->TraverseDecl(Ctx.getTranslationUnitDecl()); NamePostfix = NameQueryWrap->getMaxNamePostfix() + 1; FunctionVisitor->TraverseDecl(CurrentFD); StmtVisitor->TraverseDecl(TheCaller); TransAssert(TheStmt && "NULL TheStmt!"); replaceCallExpr(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool SimpleInliner::isValidArgExpr(const Expr *E) { TransAssert(E && "NULL Expr!"); switch(E->getStmtClass()) { case Expr::FloatingLiteralClass: case Expr::StringLiteralClass: case Expr::IntegerLiteralClass: case Expr::GNUNullExprClass: case Expr::CharacterLiteralClass: // Fall-through return true; case Expr::ParenExprClass: return isValidArgExpr(cast(E)->getSubExpr()); case Expr::ImplicitCastExprClass: case Expr::CStyleCastExprClass: // Fall-through return isValidArgExpr(cast(E)->getSubExpr()); case Expr::MemberExprClass: return true; case Expr::ArraySubscriptExprClass: { const ArraySubscriptExpr *AE = cast(E); return isValidArgExpr(AE->getIdx()); } case Expr::DeclRefExprClass: return true; default: return false; } TransAssert(0 && "Unreachable code!"); return false; } bool SimpleInliner::hasValidArgExprs(const CallExpr *CE) { for(CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { const Expr *Exp = *I; if (!isValidArgExpr(Exp)) return false; } return true; } void SimpleInliner::getValidFunctionDecls(void) { for (FunctionDeclToNumStmtsMap::iterator I = FunctionDeclNumStmts.begin(), E = FunctionDeclNumStmts.end(); I != E; ++I) { FunctionDecl *FD = (*I).first; unsigned int NumStmts = (*I).second; unsigned int NumCalls = FunctionDeclNumCalls[FD]; if (((NumCalls == 1) && (NumStmts <= SingleMaxNumStmts)) || ((NumCalls > 1) && (NumStmts <= MaxNumStmts))) { ValidFunctionDecls.insert(FD); } } } void SimpleInliner::doAnalysis(void) { getValidFunctionDecls(); for (SmallVector::iterator CI = AllCallExprs.begin(), CE = AllCallExprs.end(); CI != CE; ++CI) { FunctionDecl *CalleeDecl = (*CI)->getDirectCallee(); TransAssert(CalleeDecl && "Bad CalleeDecl!"); FunctionDecl *CanonicalDecl = CalleeDecl->getCanonicalDecl(); if (!ValidFunctionDecls.count(CanonicalDecl)) continue; if (!hasValidArgExprs(*CI)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) { // It's possible the direct callee is not a definition if (!CalleeDecl->isThisDeclarationADefinition()) { CalleeDecl = CalleeDecl->getCanonicalDecl(); for(FunctionDecl::redecl_iterator RI = CalleeDecl->redecls_begin(), RE = CalleeDecl->redecls_end(); RI != RE; ++RI) { if ((*RI)->isThisDeclarationADefinition()) { CalleeDecl = (*RI); break; } } } TransAssert(CalleeDecl->isThisDeclarationADefinition() && "Bad CalleeDecl!"); CurrentFD = CalleeDecl; TheCaller = CalleeToCallerMap[(*CI)]; TransAssert(TheCaller && "NULL TheCaller!"); TheCallExpr = (*CI); } } } std::string SimpleInliner::getNewTmpName(void) { std::stringstream SS; SS << RewriteHelper->getTmpVarNamePrefix() << NamePostfix; NamePostfix++; return SS.str(); } void SimpleInliner::createReturnVar(void) { const Type *FDType = CurrentFD->getReturnType().getTypePtr(); const Type *CallExprType = TheCallExpr->getCallReturnType(CurrentFD->getASTContext()).getTypePtr(); // We don't need tmp var if (FDType->isVoidType() && CallExprType->isVoidType()) { return; } TmpVarName = getNewTmpName(); std::string VarStr = TmpVarName; CurrentFD->getReturnType().getAsStringInternal(VarStr, Context->getPrintingPolicy()); VarStr += ";"; RewriteHelper->addLocalVarToFunc(VarStr, TheCaller); } bool SimpleInliner::hasNameClash(const std::string &ParmName, const Expr *E) { E = E->IgnoreParenCasts(); const DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return false; return ParmName == DRE->getDecl()->getNameAsString(); } void SimpleInliner::generateParamStrings(void) { unsigned int ArgNum = TheCallExpr->getNumArgs(); FunctionDecl *FD = TheCallExpr->getDirectCallee(); unsigned int Idx; for(Idx = 0; Idx < FD->getNumParams(); ++Idx) { const ParmVarDecl *PD = FD->getParamDecl(Idx); std::string ParmStr = PD->getNameAsString(); if (Idx < ArgNum) { const Expr *Arg = TheCallExpr->getArg(Idx); std::string ArgStr; RewriteHelper->getExprString(Arg, ArgStr); // create a new tmp for parms with name clash if (hasNameClash(ParmStr, Arg)) { std::string TmpName = getNewTmpName(); std::string NewParmStr = TmpName; PD->getType().getAsStringInternal(NewParmStr, Context->getPrintingPolicy()); ParmsWithNameClash.push_back(NewParmStr + " = " + ArgStr + ";\n"); ArgStr = TmpName; } PD->getType().getAsStringInternal(ParmStr, Context->getPrintingPolicy()); ParmStr += " = " + ArgStr; } else { PD->getType().getAsStringInternal(ParmStr, Context->getPrintingPolicy()); } ParmStr += ";\n"; ParmStrings.push_back(ParmStr); } } void SimpleInliner::insertReturnStmt (std::vector< std::pair > &SortedReturnStmts, ReturnStmt *RS, int Off) { std::pair ReturnStmtOffPair(RS, Off); if (SortedReturnStmts.empty()) { SortedReturnStmts.push_back(ReturnStmtOffPair); return; } std::vector< std::pair >::iterator I, E; for(I = SortedReturnStmts.begin(), E = SortedReturnStmts.end(); I != E; ++I) { int TmpOff = (*I).second; if (Off < TmpOff) break; } if (I == E) SortedReturnStmts.push_back(ReturnStmtOffPair); else SortedReturnStmts.insert(I, ReturnStmtOffPair); } void SimpleInliner::sortReturnStmtsByOffs(const char *StartBuf, std::vector< std::pair > &SortedReturnStmts) { for (ReturnStmtsVector::iterator I = ReturnStmts.begin(), E = ReturnStmts.end(); I != E; ++I) { ReturnStmt *RS = (*I); SourceLocation RSLocStart = RS->getBeginLoc(); const char *RSStartBuf = SrcManager->getCharacterData(RSLocStart); int Off = RSStartBuf - StartBuf; TransAssert((Off >= 0) && "Bad Offset!"); insertReturnStmt(SortedReturnStmts, RS, Off); } } void SimpleInliner::copyFunctionBody(void) { Stmt *Body = CurrentFD->getBody(); TransAssert(Body && "NULL Body!"); std::string FuncBodyStr(""); RewriteHelper->getStmtString(Body, FuncBodyStr); TransAssert(FuncBodyStr[0] == '{'); SourceLocation StartLoc = Body->getBeginLoc(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::vector< std::pair > SortedReturnStmts; sortReturnStmtsByOffs(StartBuf, SortedReturnStmts); // Now we start rewriting int Delta = 1; // skip the first { symbol for(SmallVector::iterator I = ParmStrings.begin(), E = ParmStrings.end(); I != E; ++I) { std::string PStr = (*I); FuncBodyStr.insert(Delta, PStr); Delta += PStr.size(); } // restore the effect of { Delta--; int ReturnSZ = 6; std::string TmpVarStr = TmpVarName + " = "; int TmpVarNameSize = static_cast(TmpVarStr.size()); for(std::vector< std::pair >::iterator I = SortedReturnStmts.begin(), E = SortedReturnStmts.end(); I != E; ++I) { ReturnStmt *RS = (*I).first; int Off = (*I).second + Delta; Expr *Exp = RS->getRetValue(); if (Exp) { const Type *T = Exp->getType().getTypePtr(); if (!T->isVoidType()) { FuncBodyStr.replace(Off, ReturnSZ, TmpVarStr); Delta += (TmpVarNameSize - ReturnSZ); continue; } } FuncBodyStr.replace(Off, ReturnSZ, ""); Delta -= ReturnSZ; } if (ParmsWithNameClash.size()) { std::string ExtraStr; for (auto Parm : ParmsWithNameClash) { ExtraStr += Parm; } FuncBodyStr = "{\n" + ExtraStr + FuncBodyStr + "}\n"; } RewriteHelper->addStringBeforeStmt(TheStmt, FuncBodyStr, NeedParen); } void SimpleInliner::removeFunctionBody(void) { if (FunctionDecl *FD = CurrentFD->getInstantiatedFromMemberFunction()) { CXXMethodDecl *MD = dyn_cast(FD); // CurrentFD is instantiated from a member function. Extend the source // begin to the outer template keyword. if (MD && MD->getParent()->getDescribedClassTemplate()) { CXXMethodDecl *MostRecent = MD->getMostRecentDecl(); if (MostRecent != MD) { TheRewriter.RemoveText(MostRecent->getSourceRange()); return; } } } if (FunctionTemplateDecl *FTD = CurrentFD->getPrimaryTemplate()) { if (FTD->getBeginLoc().isValid() && FTD->getEndLoc().isValid()) { TheRewriter.RemoveText(FTD->getSourceRange()); return; } } SourceRange FDRange = CurrentFD->getSourceRange(); TheRewriter.RemoveText(FDRange); } void SimpleInliner::replaceCallExpr(void) { // Create a new tmp var for return value createReturnVar(); // reset ParmsWithNameClash ParmsWithNameClash.clear(); generateParamStrings(); copyFunctionBody(); RewriteHelper->replaceExprNotInclude(TheCallExpr, TmpVarName); FunctionDecl *CanonicalFD = CurrentFD->getCanonicalDecl(); if (FunctionDeclNumCalls[CanonicalFD] == 1) removeFunctionBody(); } SimpleInliner::~SimpleInliner(void) { delete NameQueryWrap; delete CollectionVisitor; delete FunctionVisitor; delete FunctionStmtVisitor; delete StmtVisitor; } cvise-2.3.0/clang_delta/SimpleInliner.h000066400000000000000000000100331402162750500200040ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLE_INLINER_H #define SIMPLE_INLINER_H #include #include #include #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class CallExpr; class DeclRefExpr; class ReturnStmt; class Expr; class Stmt; } class SimpleInlinerCollectionVisitor; class SimpleInlinerFunctionVisitor; class SimpleInlinerFunctionStmtVisitor; class SimpleInlinerStmtVisitor; class SimpleInliner : public Transformation { friend class SimpleInlinerCollectionVisitor; friend class SimpleInlinerFunctionVisitor; friend class SimpleInlinerFunctionStmtVisitor; friend class SimpleInlinerStmtVisitor; public: SimpleInliner(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), FunctionVisitor(NULL), FunctionStmtVisitor(NULL), StmtVisitor(NULL), NameQueryWrap(NULL), TheCallExpr(NULL), TheCaller(NULL), CurrentFD(NULL), TheStmt(NULL), SingleMaxNumStmts(25), MaxNumStmts(10), TmpVarName(""), NeedParen(false), NamePostfix(0) { } ~SimpleInliner(void); private: typedef llvm::SmallVector ReturnStmtsVector; typedef llvm::SmallVector ParmRefsVector; typedef llvm::DenseMap FunctionDeclToNumCallsMap; typedef llvm::DenseMap FunctionDeclToNumStmtsMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void replaceCallExpr(void); void doAnalysis(void); bool isValidArgExpr(const clang::Expr *E); bool hasValidArgExprs(const clang::CallExpr *CE); void createReturnVar(void); void generateParamStrings(void); void copyFunctionBody(void); std::string getNewTmpName(void); void getValidFunctionDecls(void); void removeFunctionBody(void); void sortReturnStmtsByOffs(const char *StartBuf, std::vector< std::pair > &SortedReturnStmts); void insertReturnStmt (std::vector< std::pair > &SortedReturnStmts, clang::ReturnStmt *RS, int Off); bool hasNameClash(const std::string &ParmName, const clang::Expr *E); FunctionDeclToNumCallsMap FunctionDeclNumCalls; FunctionDeclToNumStmtsMap FunctionDeclNumStmts; llvm::DenseMap CalleeToCallerMap; llvm::SmallVector AllCallExprs; llvm::SmallSet ValidFunctionDecls; llvm::SmallVector ParmStrings; llvm::SmallVector ParmsWithNameClash; ReturnStmtsVector ReturnStmts; ParmRefsVector ParmRefs; SimpleInlinerCollectionVisitor *CollectionVisitor; SimpleInlinerFunctionVisitor *FunctionVisitor; SimpleInlinerFunctionStmtVisitor *FunctionStmtVisitor; SimpleInlinerStmtVisitor *StmtVisitor; TransNameQueryWrap *NameQueryWrap; clang::CallExpr *TheCallExpr; clang::FunctionDecl *TheCaller; clang::FunctionDecl *CurrentFD; clang::Stmt *TheStmt; // MaxNumStmts for a function with single call site const unsigned int SingleMaxNumStmts; // MaxNumStmts for a function with multiple call sites const unsigned int MaxNumStmts; std::string TmpVarName; bool NeedParen; unsigned int NamePostfix; // Unimplemented SimpleInliner(void); SimpleInliner(const SimpleInliner &); void operator=(const SimpleInliner &); }; #endif cvise-2.3.0/clang_delta/SimplifyCallExpr.cpp000066400000000000000000000116261402162750500210250ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyCallExpr.h" #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Simplify a call expression to a comma expression. \ Replace function arguments with: \n\ * 0 for integer and pointer arguments \n\ * a global temp variable for structs/unions \ and also append a representative return value which is the \ the last inner expression of the comma expression. \n\ For example, assume we have a function foo: \n\ int foo(int x, int *y, struct z) \ Then this transformation will transform \n\ foo(i, p, s); \n\ to \n\ (0, 0, tmp_var, 0);\n"; static RegisterTransformation Trans("simplify-callexpr", DescriptionMsg); class SimplifyCallExprVisitor : public RecursiveASTVisitor { public: explicit SimplifyCallExprVisitor(SimplifyCallExpr *Instance) : ConsumerInstance(Instance), CurrentFD(NULL) { } bool VisitCallExpr(CallExpr *CE); bool VisitFunctionDecl(FunctionDecl *FD); private: SimplifyCallExpr *ConsumerInstance; const FunctionDecl *CurrentFD; }; bool SimplifyCallExprVisitor::VisitCallExpr(CallExpr *CE) { if (ConsumerInstance->isInIncludedFile(CE)) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->TransformationCounter != ConsumerInstance->ValidInstanceNum) return true; ConsumerInstance->TheCallExpr = CE; ConsumerInstance->CurrentFD = CurrentFD; return true; } bool SimplifyCallExprVisitor::VisitFunctionDecl(FunctionDecl *FD) { CurrentFD = FD; return true; } void SimplifyCallExpr::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new SimplifyCallExprVisitor(this); NameQueryWrap = new TransNameQueryWrap(RewriteHelper->getTmpVarNamePrefix()); } void SimplifyCallExpr::HandleTranslationUnit(ASTContext &Ctx) { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheCallExpr && "NULL TheCallExpr!"); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); NameQueryWrap->TraverseDecl(Ctx.getTranslationUnitDecl()); NamePostfix = NameQueryWrap->getMaxNamePostfix() + 1; replaceCallExpr(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyCallExpr::handleOneArgStr(const Expr *Arg, std::string &Str) { Str = "0"; const Type *ArgT = Arg->getType().getTypePtr(); if (!ArgT->isUnionType() && !ArgT->isStructureType()) return; RewriteHelper->getTmpTransName(NamePostfix, Str); NamePostfix++; std::string TmpVarStr = Str; Arg->getType().getAsStringInternal(TmpVarStr, Context->getPrintingPolicy()); TmpVarStr += ";\n"; if (CurrentFD) { RewriteHelper->insertStringBeforeFunc(CurrentFD, TmpVarStr); } else { TheRewriter.InsertTextBefore(getRealLocation(TheCallExpr->getBeginLoc()), TmpVarStr); } } void SimplifyCallExpr::replaceCallExpr(void) { std::string CommaStr(""); unsigned int NumArg = TheCallExpr->getNumArgs(); if (NumArg == 0) { RewriteHelper->replaceExpr(TheCallExpr, CommaStr); return; } const Expr *Arg = TheCallExpr->getArg(0); std::string ArgStr; handleOneArgStr(Arg, ArgStr); CommaStr += ("(" + ArgStr); for (unsigned int I = 1; I < NumArg; ++I) { Arg = TheCallExpr->getArg(I); handleOneArgStr(Arg, ArgStr); CommaStr += ("," + ArgStr); } QualType RVQualType = TheCallExpr->getType(); const Type *RVType = RVQualType.getTypePtr(); if (RVType->isVoidType()) { // Nothing to do } else if (RVType->isUnionType() || RVType->isStructureType()) { std::string RVStr(""); RewriteHelper->getTmpTransName(NamePostfix, RVStr); NamePostfix++; CommaStr += ("," + RVStr); RVQualType.getAsStringInternal(RVStr, Context->getPrintingPolicy()); RVStr += ";\n"; if (CurrentFD) { RewriteHelper->insertStringBeforeFunc(CurrentFD, RVStr); } else { TheRewriter.InsertTextBefore(getRealLocation(TheCallExpr->getBeginLoc()), RVStr); } } else { CommaStr += ",0"; } CommaStr += ")"; RewriteHelper->replaceExpr(TheCallExpr, CommaStr); } SimplifyCallExpr::~SimplifyCallExpr(void) { delete CollectionVisitor; delete NameQueryWrap; } cvise-2.3.0/clang_delta/SimplifyCallExpr.h000066400000000000000000000030101402162750500204560ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_CALL_EXPR_H #define SIMPLIFY_CALL_EXPR_H #include #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; class CallExpr; class Expr; } class SimplifyCallExprVisitor; class SimplifyCallExpr : public Transformation { friend class SimplifyCallExprVisitor; public: SimplifyCallExpr(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), NameQueryWrap(NULL), TheCallExpr(NULL), CurrentFD(NULL), NamePostfix(0) { } ~SimplifyCallExpr(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneArgStr(const clang::Expr *Arg, std::string &Str); void replaceCallExpr(void); SimplifyCallExprVisitor *CollectionVisitor; TransNameQueryWrap *NameQueryWrap; const clang::CallExpr *TheCallExpr; const clang::FunctionDecl *CurrentFD; unsigned int NamePostfix; // Unimplemented SimplifyCallExpr(void); SimplifyCallExpr(const SimplifyCallExpr &); void operator=(const SimplifyCallExpr &); }; #endif cvise-2.3.0/clang_delta/SimplifyCommaExpr.cpp000066400000000000000000000122041402162750500211770ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyCommaExpr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonStatementVisitor.h" using namespace clang; static const char *DescriptionMsg = "Simplify a comma expression. It transforms the following code: \n\ (x, y); \n\ to \n\ x; \n\ (y); \n"; static RegisterTransformation Trans("simplify-comma-expr", DescriptionMsg); class SimplifyCommaExprCollectionVisitor : public RecursiveASTVisitor { public: explicit SimplifyCommaExprCollectionVisitor(SimplifyCommaExpr *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: SimplifyCommaExpr *ConsumerInstance; }; class SimplifyCommaExprStmtVisitor : public CommonStatementVisitor { public: explicit SimplifyCommaExprStmtVisitor(SimplifyCommaExpr *Instance) : ConsumerInstance(Instance) { } bool VisitForStmt(ForStmt *FS); bool VisitWhileStmt(WhileStmt *WS); bool VisitDoStmt(DoStmt *DS); bool VisitBinaryOperator(BinaryOperator *BO); private: SimplifyCommaExpr *ConsumerInstance; }; bool SimplifyCommaExprCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || !FD->isThisDeclarationADefinition()) return true; ConsumerInstance->StmtVisitor->TraverseDecl(FD); return true; } // It causes unsound transformation because // the semantics of loop execution has been changed. // For example, // int foo(int x) // { // int i; // for(i = 0; i < bar(bar(x)); i++) // ... // } // will be transformed to: // int foo(int x) // { // int i; // int tmp_var = bar(x); // for(i = 0; i < bar(tmp_var); i++) // ... // } bool SimplifyCommaExprStmtVisitor::VisitForStmt(ForStmt *FS) { Stmt *Body = FS->getBody(); visitNonCompoundStmt(Body); return false; } bool SimplifyCommaExprStmtVisitor::VisitWhileStmt(WhileStmt *WS) { Stmt *Body = WS->getBody(); visitNonCompoundStmt(Body); return false; } bool SimplifyCommaExprStmtVisitor::VisitDoStmt(DoStmt *DS) { Stmt *Body = DS->getBody(); visitNonCompoundStmt(Body); return false; } bool SimplifyCommaExprStmtVisitor::VisitBinaryOperator( BinaryOperator *BO) { BinaryOperator::Opcode Op = BO->getOpcode(); if (Op == clang::BO_Comma) { ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheBinaryOperator = BO; ConsumerInstance->TheStmt = CurrentStmt; ConsumerInstance->NeedParen = NeedParen; } } Expr *LHS = BO->getLHS(); TraverseStmt(LHS); Expr *RHS = BO->getRHS(); TraverseStmt(RHS); return false; } void SimplifyCommaExpr::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new SimplifyCommaExprCollectionVisitor(this); StmtVisitor = new SimplifyCommaExprStmtVisitor(this); } bool SimplifyCommaExpr::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void SimplifyCommaExpr::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheStmt && "NULL TheStmt!"); TransAssert(TheBinaryOperator && "NULL TheBinaryOperator"); simplifyCommaExpr(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyCommaExpr::simplifyCommaExpr(void) { TransAssert((TheBinaryOperator->getOpcode() == clang::BO_Comma) && "Non Comma Operator!"); const Expr *LHS = TheBinaryOperator->getLHS(); std::string LHSStr; RewriteHelper->getExprString(LHS, LHSStr); SourceRange LHSRange = LHS->getSourceRange(); SourceLocation StartLoc = LHSRange.getBegin(); SourceLocation EndLoc; if (StartLoc.isMacroID()) { StartLoc = SrcManager->getFileLoc(StartLoc); EndLoc = LHSRange.getEnd(); TransAssert(EndLoc.isMacroID() && "EndLoc is not from a macro!"); LHSRange = SourceRange(StartLoc, SrcManager->getFileLoc(EndLoc)); } EndLoc = RewriteHelper->getEndLocationUntil(LHSRange, ','); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); LHSStr += ";"; RewriteHelper->addStringBeforeStmt(TheStmt, LHSStr, NeedParen); } SimplifyCommaExpr::~SimplifyCommaExpr(void) { delete CollectionVisitor; delete StmtVisitor; } cvise-2.3.0/clang_delta/SimplifyCommaExpr.h000066400000000000000000000031431402162750500206460ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_COMMA_EXPR_H #define SIMPLIFY_COMMA_EXPR_H #include #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class Stmt; class BinaryOperator; } class SimplifyCommaExprCollectionVisitor; class SimplifyCommaExprStmtVisitor; class SimplifyCommaExpr : public Transformation { friend class SimplifyCommaExprCollectionVisitor; friend class SimplifyCommaExprStmtVisitor; public: SimplifyCommaExpr(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), StmtVisitor(NULL), TheBinaryOperator(NULL), TheStmt(NULL), NeedParen(false) { } ~SimplifyCommaExpr(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void simplifyCommaExpr(void); SimplifyCommaExprCollectionVisitor *CollectionVisitor; SimplifyCommaExprStmtVisitor *StmtVisitor; clang::BinaryOperator *TheBinaryOperator; clang::Stmt *TheStmt; bool NeedParen; // Unimplemented SimplifyCommaExpr(void); SimplifyCommaExpr(const SimplifyCommaExpr &); void operator=(const SimplifyCommaExpr &); }; #endif cvise-2.3.0/clang_delta/SimplifyDependentTypedef.cpp000066400000000000000000000144451402162750500225440ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyDependentTypedef.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Sometimes the underlying type of a typedef declaration \ is a complex dependent type which prevents further reduction. \ This pass tries to replace this complex dependent type with a \ simple one. For example, from \n\ template class { \n\ typedef typename X< typename Y >::type type; \n\ }; \n\ to \n\ template class { \n\ typedef T type; \n\ };\n"; static RegisterTransformation Trans("simplify-dependent-typedef", DescriptionMsg); class DependentTypedefCollectionVisitor : public RecursiveASTVisitor { public: explicit DependentTypedefCollectionVisitor(SimplifyDependentTypedef *Instance) : ConsumerInstance(Instance) { } bool VisitTypedefDecl(TypedefDecl *D); private: SimplifyDependentTypedef *ConsumerInstance; }; class DependentTypedefTemplateTypeParmTypeVisitor : public RecursiveASTVisitor { typedef llvm::SmallPtrSet TemplateTypeParmTypeSet; public: explicit DependentTypedefTemplateTypeParmTypeVisitor( SimplifyDependentTypedef *Instance) : IsValidType(false) { } bool VisitTemplateTypeParmType(TemplateTypeParmType *Ty); void setTypeSet(TemplateTypeParmTypeSet *Set) { TypeSet = Set; } void setValidType(bool Valid) { IsValidType = Valid; } bool isValidType(void) { return IsValidType; } private: TemplateTypeParmTypeSet *TypeSet; bool IsValidType; }; bool DependentTypedefCollectionVisitor::VisitTypedefDecl(TypedefDecl *D) { ConsumerInstance->handleOneTypedefDecl(D); return true; } bool DependentTypedefTemplateTypeParmTypeVisitor::VisitTemplateTypeParmType( TemplateTypeParmType *Ty) { const Type *CanonicalTy = Ty->getCanonicalTypeInternal().getTypePtr(); if (TypeSet->count(CanonicalTy)) { IsValidType = true; return false; } return true; } void SimplifyDependentTypedef::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new DependentTypedefCollectionVisitor(this); TemplateTypeParmTypeVisitor = new DependentTypedefTemplateTypeParmTypeVisitor(this); } void SimplifyDependentTypedef::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheTypedefDecl && "NULL TheTypedefDecl!"); TransAssert(FirstTmplTypeParmD && "NULL FirstTmplTypeParmD!"); rewriteTypedefDecl(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyDependentTypedef::rewriteTypedefDecl(void) { SourceLocation LocStart = TheTypedefDecl->getBeginLoc(); // skip "typedef " LocStart = LocStart.getLocWithOffset(8); SourceLocation LocEnd = TheTypedefDecl->getLocation(); LocEnd = LocEnd.getLocWithOffset(-1); std::string ParmName = FirstTmplTypeParmD->getNameAsString(); TransAssert(!ParmName.empty() && "Invalid TypeParmType Name!"); // make an explicit blank after the type name in case we // have typedef XXXtype; TheRewriter.ReplaceText(SourceRange(LocStart, LocEnd), ParmName+" "); } void SimplifyDependentTypedef::handleOneTypedefDecl(const TypedefDecl *D) { if (isInIncludedFile(D)) return; const TypedefDecl *CanonicalD = dyn_cast(D->getCanonicalDecl()); TransAssert(CanonicalD && "Bad TypedefDecl!"); if (VisitedTypedefDecls.count(CanonicalD)) return; VisitedTypedefDecls.insert(CanonicalD); const CXXRecordDecl *CXXRD = dyn_cast(D->getDeclContext()); if (!CXXRD) return; const ClassTemplateDecl *TmplD = CXXRD->getDescribedClassTemplate(); if (!TmplD) return; TemplateParameterList *TmplParmList = TmplD->getTemplateParameters(); if (TmplParmList->size() == 0) return; TemplateTypeParmTypeSet TypeSet; const TemplateTypeParmDecl *FirstParmD = NULL; for (TemplateParameterList::iterator I = TmplParmList->begin(), E = TmplParmList->end(); I != E; ++I) { if (const TemplateTypeParmDecl *TmplTypeParmD = dyn_cast(*I)) { if (!FirstParmD && !TmplTypeParmD->getNameAsString().empty()) FirstParmD = TmplTypeParmD; const TemplateTypeParmType *TmplParmTy = dyn_cast(TmplTypeParmD->getTypeForDecl()); TransAssert(TmplParmTy && "Bad TemplateTypeParmType!"); TypeSet.insert(TmplParmTy->getCanonicalTypeInternal().getTypePtr()); } } if (!FirstParmD) return; QualType QT = CanonicalD->getUnderlyingType(); const Type *Ty = QT.getTypePtr(); Type::TypeClass TC = Ty->getTypeClass(); if ((TC != Type::DependentName) && (TC != Type::DependentTemplateSpecialization) && (TC != Type::TemplateSpecialization) && (TC != Type::Elaborated)) return; TemplateTypeParmTypeVisitor->setTypeSet(&TypeSet); TemplateTypeParmTypeVisitor->setValidType(false); TemplateTypeParmTypeVisitor->TraverseType(QT); if (!TemplateTypeParmTypeVisitor->isValidType()) return; ValidInstanceNum++; if (ValidInstanceNum != TransformationCounter) return; FirstTmplTypeParmD = FirstParmD; TheTypedefDecl = CanonicalD; } SimplifyDependentTypedef::~SimplifyDependentTypedef(void) { delete CollectionVisitor; delete TemplateTypeParmTypeVisitor; } cvise-2.3.0/clang_delta/SimplifyDependentTypedef.h000066400000000000000000000037101402162750500222020ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_DEPENDENT_TYPEDEF_H #define SIMPLIFY_DEPENDENT_TYPEDEF_H #include "Transformation.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { class DeclGroupRef; class ASTContext; class TypedefDecl; class ClassTemplateDecl; class TemplateTypeParmDecl; } class DependentTypedefCollectionVisitor; class DependentTypedefTemplateTypeParmTypeVisitor; class SimplifyDependentTypedef : public Transformation { friend class DependentTypedefCollectionVisitor; friend class DependentTypedefTemplateTypeParmTypeVisitor; public: SimplifyDependentTypedef(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TemplateTypeParmTypeVisitor(NULL), FirstTmplTypeParmD(NULL) {} ~SimplifyDependentTypedef(void); private: typedef llvm::SmallPtrSet TypedefDeclsSet; typedef llvm::SmallPtrSet TemplateTypeParmTypeSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneTypedefDecl(const clang::TypedefDecl *D); void rewriteTypedefDecl(void); TypedefDeclsSet VisitedTypedefDecls; DependentTypedefCollectionVisitor *CollectionVisitor; DependentTypedefTemplateTypeParmTypeVisitor *TemplateTypeParmTypeVisitor; const clang::TemplateTypeParmDecl *FirstTmplTypeParmD; const clang::TypedefDecl *TheTypedefDecl; // Unimplemented SimplifyDependentTypedef(void); SimplifyDependentTypedef(const SimplifyDependentTypedef &); void operator=(const SimplifyDependentTypedef &); }; #endif cvise-2.3.0/clang_delta/SimplifyIf.cpp000066400000000000000000000116671402162750500176560ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyIf.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonStatementVisitor.h" using namespace clang; static const char *DescriptionMsg = "Simplify an if-else statement. It transforms the following code: \n\ if (guard1) \n\ {... } \n\ else if (guard2) \n\ else \n\ {...} \n\ to \n\ (guard1) \n\ {... } \n\ if (guard2) \n\ else \n\ {...} \n\ if there is no else-if left, the last else keyword will be removed. \n"; class SimplifyIfCollectionVisitor : public RecursiveASTVisitor { public: explicit SimplifyIfCollectionVisitor(SimplifyIf *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); private: SimplifyIf *ConsumerInstance; }; static RegisterTransformation Trans("simplify-if", DescriptionMsg); class SimplifyIfStatementVisitor : public CommonStatementVisitor { public: explicit SimplifyIfStatementVisitor(SimplifyIf *Instance) : ConsumerInstance(Instance) { } bool VisitIfStmt(IfStmt *IS); bool VisitForStmt(ForStmt *FS); bool VisitWhileStmt(WhileStmt *WS); bool VisitDoStmt(DoStmt *DS); private: SimplifyIf *ConsumerInstance; }; bool SimplifyIfCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { if (ConsumerInstance->isInIncludedFile(FD) || !FD->isThisDeclarationADefinition()) return true; ConsumerInstance->StmtVisitor->TraverseDecl(FD); return true; } // It is used to handle the case where if-then or else branch // is not treated as a CompoundStmt. So it cannot be traversed // from VisitCompoundStmt, e.g., // if (x) // foo(bar()) bool SimplifyIfStatementVisitor::VisitIfStmt(IfStmt *IS) { if (IS->getBeginLoc().isMacroID()) { return false; } ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheIfStmt = IS; ConsumerInstance->NeedParen = NeedParen; } Stmt *ThenB = IS->getThen(); visitNonCompoundStmt(ThenB); Stmt *ElseB = IS->getElse(); visitNonCompoundStmt(ElseB); return false; } // It causes unsound transformation because // the semantics of loop execution has been changed. // For example, // int foo(int x) // { // int i; // for(i = 0; i < bar(bar(x)); i++) // ... // } // will be transformed to: // int foo(int x) // { // int i; // int tmp_var = bar(x); // for(i = 0; i < bar(tmp_var); i++) // ... // } bool SimplifyIfStatementVisitor::VisitForStmt(ForStmt *FS) { Stmt *Body = FS->getBody(); visitNonCompoundStmt(Body); return false; } bool SimplifyIfStatementVisitor::VisitWhileStmt(WhileStmt *WS) { Stmt *Body = WS->getBody(); visitNonCompoundStmt(Body); return false; } bool SimplifyIfStatementVisitor::VisitDoStmt(DoStmt *DS) { Stmt *Body = DS->getBody(); visitNonCompoundStmt(Body); return false; } void SimplifyIf::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new SimplifyIfCollectionVisitor(this); StmtVisitor = new SimplifyIfStatementVisitor(this); } bool SimplifyIf::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { CollectionVisitor->TraverseDecl(*I); } return true; } void SimplifyIf::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheIfStmt && "NULL TheIfStmt"); simplifyIfStmt(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyIf::simplifyIfStmt(void) { const Expr *Cond = TheIfStmt->getCond(); TransAssert(Cond && "Bad Cond Expr!"); std::string CondStr; RewriteHelper->getExprString(Cond, CondStr); CondStr += ";"; RewriteHelper->addStringBeforeStmt(TheIfStmt, CondStr, NeedParen); RewriteHelper->removeIfAndCond(TheIfStmt); const Stmt *ElseS = TheIfStmt->getElse(); if (ElseS) { SourceLocation ElseLoc = RewriteHelper->getRealLocation(TheIfStmt->getElseLoc()); std::string ElseStr = "else"; TheRewriter.RemoveText(ElseLoc, ElseStr.size()); } } SimplifyIf::~SimplifyIf(void) { delete CollectionVisitor; delete StmtVisitor; } cvise-2.3.0/clang_delta/SimplifyIf.h000066400000000000000000000026661402162750500173220ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_IF_H #define SIMPLIFY_IF_H #include #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class Stmt; class IfStmt; } class SimplifyIfCollectionVisitor; class SimplifyIfStatementVisitor; class SimplifyIf : public Transformation { friend class SimplifyIfCollectionVisitor; friend class SimplifyIfStatementVisitor; public: SimplifyIf(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), StmtVisitor(NULL), TheIfStmt(NULL), NeedParen(false) { } ~SimplifyIf(void); private: virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void simplifyIfStmt(void); SimplifyIfCollectionVisitor *CollectionVisitor; SimplifyIfStatementVisitor *StmtVisitor; clang::IfStmt *TheIfStmt; bool NeedParen; // Unimplemented SimplifyIf(void); SimplifyIf(const SimplifyIf &); void operator=(const SimplifyIf &); }; #endif cvise-2.3.0/clang_delta/SimplifyNestedClass.cpp000066400000000000000000000127021402162750500215170ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyNestedClass.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/Lexer.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass tries to simplify nested classes by replacing the \ outer class with the inner class, if \n\ * the outer class doesn't have any base class, and \n\ * the outer class has only one inner class definition, and \n\ * the outer class does not have any described template, and \n\ * the outer class does not have any other declarations except \ the inner class \n\ "; static RegisterTransformation Trans("simplify-nested-class", DescriptionMsg); class SimplifyNestedClassVisitor : public RecursiveASTVisitor { public: explicit SimplifyNestedClassVisitor( SimplifyNestedClass *Instance) : ConsumerInstance(Instance) { } bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD); private: SimplifyNestedClass *ConsumerInstance; }; bool SimplifyNestedClassVisitor::VisitCXXRecordDecl( CXXRecordDecl *CXXRD) { if (ConsumerInstance->isInIncludedFile(CXXRD) || ConsumerInstance->isSpecialRecordDecl(CXXRD) || !CXXRD->hasDefinition()) return true; ConsumerInstance->handleOneCXXRecordDecl(CXXRD->getDefinition()); return true; } class SimplifyNestedClassRewriteVisitor : public RecursiveASTVisitor { public: explicit SimplifyNestedClassRewriteVisitor( SimplifyNestedClass *Instance) : ConsumerInstance(Instance) { } bool VisitRecordTypeLoc(RecordTypeLoc TLoc); private: SimplifyNestedClass *ConsumerInstance; }; bool SimplifyNestedClassRewriteVisitor::VisitRecordTypeLoc(RecordTypeLoc TLoc) { const CXXRecordDecl *RD = dyn_cast(TLoc.getDecl()); if (!RD || (RD->getCanonicalDecl() != ConsumerInstance->TheBaseCXXRD->getCanonicalDecl())) return true; if (ConsumerInstance->isBeforeColonColon(TLoc)) { SourceLocation LocEnd = ConsumerInstance->RewriteHelper->getLocationAfter( TLoc.getEndLoc(), ':'); ConsumerInstance->TheRewriter.RemoveText( SourceRange(TLoc.getBeginLoc(), LocEnd)); } else { ConsumerInstance->RewriteHelper->replaceRecordType(TLoc, ConsumerInstance->TheBaseCXXRD->getNameAsString() + " "); } return true; } void SimplifyNestedClass::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new SimplifyNestedClassVisitor(this); RewriteVisitor = new SimplifyNestedClassRewriteVisitor(this); } void SimplifyNestedClass::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); removeOuterClass(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyNestedClass::removeOuterClass() { TransAssert(TheBaseCXXRD && "NULL Base CXXRD!"); SourceLocation LocStart = TheBaseCXXRD->getBeginLoc(); SourceLocation LocEnd = TheInnerDecl->getBeginLoc(); LocEnd = LocEnd.getLocWithOffset(-1); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); LocStart = TheBaseCXXRD->getBraceRange().getEnd(); LocEnd = RewriteHelper->getLocationUntil(LocStart, ';'); if (LocStart.isInvalid() || LocEnd.isInvalid()) return; TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); } void SimplifyNestedClass::handleOneCXXRecordDecl(const CXXRecordDecl *CXXRD) { TransAssert(CXXRD && "NULL CXXRD!"); TransAssert(CXXRD->isThisDeclarationADefinition() && "Not a definition!"); if (CXXRD->getDescribedClassTemplate() || CXXRD->getNumBases() || dyn_cast(CXXRD)) return; // anon class if (CXXRD->getNameAsString() == "") return; const Decl *InnerDecl = NULL; const DeclContext *Ctx = dyn_cast(CXXRD); for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if ((*I)->isImplicit() || dyn_cast(*I)) continue; if (dyn_cast(*I) || dyn_cast(*I)) { if (InnerDecl) return; InnerDecl = (*I); } else { return; } } if (!InnerDecl) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheBaseCXXRD = CXXRD; TheInnerDecl = InnerDecl; } } SimplifyNestedClass::~SimplifyNestedClass(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/SimplifyNestedClass.h000066400000000000000000000030621402162750500211630ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_NESTED_CLASS_H #define SIMPLIFY_NESTED_CLASS_H #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class CXXRecordDecl; class Decl; } class SimplifyNestedClassVisitor; class SimplifyNestedClassRewriteVisitor; class SimplifyNestedClass : public Transformation { friend class SimplifyNestedClassVisitor; friend class SimplifyNestedClassRewriteVisitor; public: SimplifyNestedClass(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheBaseCXXRD(NULL) { } ~SimplifyNestedClass(void); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneCXXRecordDecl(const clang::CXXRecordDecl *CXXRD); void removeOuterClass(); SimplifyNestedClassVisitor *CollectionVisitor; SimplifyNestedClassRewriteVisitor *RewriteVisitor; const clang::CXXRecordDecl *TheBaseCXXRD; const clang::Decl *TheInnerDecl; // Unimplemented SimplifyNestedClass(void); SimplifyNestedClass(const SimplifyNestedClass &); void operator=(const SimplifyNestedClass &); }; #endif cvise-2.3.0/clang_delta/SimplifyRecursiveTemplateInstantiation.cpp000066400000000000000000000145141402162750500255220ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyRecursiveTemplateInstantiation.h" #include "clang/Lex/Lexer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass handles a special case where we have recursive template \ instantiations. For example, given the code blow: \n\ C, G > > \n\ it will replace an outer instantiation of B with an inner one, e.g. B.\n\ The the number of transformation instances counts from inside to \n\ outside. Currently we only handle class template instantiations. \n\ "; static RegisterTransformation Trans("simplify-recursive-template-instantiation", DescriptionMsg); namespace { class LocalTemplateArgVisitor : public RecursiveASTVisitor { public: LocalTemplateArgVisitor(const TemplateSpecializationTypeLoc &TLoc, SimplifyRecursiveTemplateInstantiation *Instance) : ParentTLoc(TLoc), ConsumerInstance(Instance) { } bool VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TLoc); private: const TemplateSpecializationTypeLoc &ParentTLoc; SimplifyRecursiveTemplateInstantiation *ConsumerInstance; }; bool LocalTemplateArgVisitor::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TLoc) { ConsumerInstance->handleInnerTemplateSpecializationTypeLoc(ParentTLoc, TLoc); return true; } } // end anon namespace class SimplifyRecursiveTemplateInstantiationASTVisitor : public RecursiveASTVisitor { public: explicit SimplifyRecursiveTemplateInstantiationASTVisitor( SimplifyRecursiveTemplateInstantiation *Instance) : ConsumerInstance(Instance) { } bool VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TLoc); private: SimplifyRecursiveTemplateInstantiation *ConsumerInstance; }; bool SimplifyRecursiveTemplateInstantiationASTVisitor:: VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TLoc) { ConsumerInstance->handleTemplateSpecializationTypeLoc(TLoc); return true; } void SimplifyRecursiveTemplateInstantiation::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new SimplifyRecursiveTemplateInstantiationASTVisitor(this); } void SimplifyRecursiveTemplateInstantiation::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); analyzeLocPairs(); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); rewriteTemplateArgument(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyRecursiveTemplateInstantiation::analyzeLocPairs() { for (SpecTypeLocPairQueue::reverse_iterator I = LocPairQueue.rbegin(), E = LocPairQueue.rend(); I != E; ++I) { ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) TheLocPair = (*I); } } void SimplifyRecursiveTemplateInstantiation::handleTemplateSpecializationTypeLoc( const TemplateSpecializationTypeLoc &TLoc) { if (isInIncludedFile(TLoc.getBeginLoc())) return; for (unsigned I = 0; I < TLoc.getNumArgs(); ++I) { TemplateArgumentLoc ArgLoc = TLoc.getArgLoc(I); if (ArgLoc.getLocation().isInvalid()) continue; LocalTemplateArgVisitor ArgVisitor(TLoc, this); ArgVisitor.TraverseTemplateArgumentLoc(ArgLoc); } } const TemplateDecl * SimplifyRecursiveTemplateInstantiation::getTemplateDeclFromSpecLoc( const TemplateSpecializationTypeLoc &TLoc) { const Type *Ty = TLoc.getTypePtr(); const TemplateSpecializationType *TST = Ty->getAs(); TemplateName TplName = TST->getTemplateName(); return TplName.getAsTemplateDecl(); } void SimplifyRecursiveTemplateInstantiation:: handleInnerTemplateSpecializationTypeLoc( const TemplateSpecializationTypeLoc &ParentTLoc, const TemplateSpecializationTypeLoc &TLoc) { const TemplateDecl *ParentD = getTemplateDeclFromSpecLoc(ParentTLoc); TransAssert(ParentD && "NULL ParentD!"); const TemplateDecl *D = getTemplateDeclFromSpecLoc(TLoc); TransAssert(D && "NULL Decl!"); if (ParentD->getCanonicalDecl() != D->getCanonicalDecl()) return; SpecTypeLocPair *P = new SpecTypeLocPair(); TransAssert(P && "Failed to alloc SpecTypeLocPair!"); P->push_back(ParentTLoc); P->push_back(TLoc); LocPairQueue.push_back(P); } void SimplifyRecursiveTemplateInstantiation::rewriteTemplateArgument() { TransAssert(TheLocPair && "NULL TheLocPair!"); TransAssert((TheLocPair->size() == 2) && "Invalid size of TheLocPair!"); TemplateSpecializationTypeLoc TLoc = TheLocPair->pop_back_val(); TemplateSpecializationTypeLoc ParentTLoc = TheLocPair->pop_back_val(); SourceLocation LAngleLoc = getRealLocation(TLoc.getLAngleLoc()); SourceLocation RAngleLoc = getRealLocation(TLoc.getRAngleLoc()); SourceLocation ParentLAngleLoc = getRealLocation(ParentTLoc.getLAngleLoc()); SourceLocation ParentRAngleLoc = getRealLocation(ParentTLoc.getRAngleLoc()); std::string InnerStr = ""; RewriteHelper->getStringBetweenLocs(InnerStr, LAngleLoc, RAngleLoc); TheRewriter.ReplaceText(SourceRange(ParentLAngleLoc, ParentRAngleLoc), InnerStr + ">"); } SimplifyRecursiveTemplateInstantiation:: ~SimplifyRecursiveTemplateInstantiation() { for (SpecTypeLocPairQueue::iterator I = LocPairQueue.begin(), E = LocPairQueue.end(); I != E; ++I) { delete (*I); } delete CollectionVisitor; } cvise-2.3.0/clang_delta/SimplifyRecursiveTemplateInstantiation.h000066400000000000000000000043431402162750500251660ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_RECURSIVE_TEMPLATE_INSTANTIATION_H #define SIMPLIFY_RECURSIVE_TEMPLATE_INSTANTIATION_H #include "llvm/ADT/SmallVector.h" #include "clang/AST/TypeLoc.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class TemplateDecl; } class SimplifyRecursiveTemplateInstantiationASTVisitor; class SimplifyRecursiveTemplateInstantiation : public Transformation { friend class SimplifyRecursiveTemplateInstantiationASTVisitor; public: SimplifyRecursiveTemplateInstantiation(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheLocPair(NULL) {} ~SimplifyRecursiveTemplateInstantiation(); void handleInnerTemplateSpecializationTypeLoc( const clang::TemplateSpecializationTypeLoc &ParentTLoc, const clang::TemplateSpecializationTypeLoc &TLoc); private: typedef llvm::SmallVector SpecTypeLocPair; typedef llvm::SmallVector SpecTypeLocPairQueue; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleTemplateSpecializationTypeLoc( const clang::TemplateSpecializationTypeLoc &TLoc); const clang::TemplateDecl * getTemplateDeclFromSpecLoc(const clang::TemplateSpecializationTypeLoc &TLoc); void rewriteTemplateArgument(); void analyzeLocPairs(); SpecTypeLocPairQueue LocPairQueue; SimplifyRecursiveTemplateInstantiationASTVisitor *CollectionVisitor; SpecTypeLocPair *TheLocPair; // Unimplemented SimplifyRecursiveTemplateInstantiation(); SimplifyRecursiveTemplateInstantiation( const SimplifyRecursiveTemplateInstantiation &); void operator=(const SimplifyRecursiveTemplateInstantiation &); }; #endif cvise-2.3.0/clang_delta/SimplifyStruct.cpp000066400000000000000000000234741402162750500206030ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyStruct.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Lex/Lexer.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "clang/AST/RecordLayout.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass replaces a struct with its parent if it has only one \ field, and this field is a struct, e.g, \n\ struct S1 { \n\ int f1;\n\ int f2;\n\ }\n\ struct S2 { \n\ struct S1 f1;\n\ } \n\ In the above code, struct S2 will be replaced with struct S1, including\n\ all its referenced. \n"; static RegisterTransformation Trans("simplify-struct", DescriptionMsg); class SimplifyStructCollectionVisitor : public RecursiveASTVisitor { public: explicit SimplifyStructCollectionVisitor(SimplifyStruct *Instance) : ConsumerInstance(Instance) { } bool VisitRecordDecl(RecordDecl *RD); private: SimplifyStruct *ConsumerInstance; }; class SimplifyStructRewriteVisitor : public RecursiveASTVisitor { public: explicit SimplifyStructRewriteVisitor(SimplifyStruct *Instance) : ConsumerInstance(Instance) { } bool VisitVarDecl(VarDecl *VD); bool VisitRecordDecl(RecordDecl *RD); bool VisitRecordTypeLoc(RecordTypeLoc RTLoc); bool VisitMemberExpr(MemberExpr *ME); private: SimplifyStruct *ConsumerInstance; }; bool SimplifyStructCollectionVisitor::VisitRecordDecl(RecordDecl *RD) { if (ConsumerInstance->isInIncludedFile(RD)) return true; if (!RD->isThisDeclarationADefinition() || !RD->isStruct()) return true; if (ConsumerInstance->isSpecialRecordDecl(RD)) return true; if (RD->isInvalidDecl()) return true; const ASTRecordLayout &Info = ConsumerInstance->Context->getASTRecordLayout(RD); unsigned Count = Info.getFieldCount(); if (Count != 1) return true; const FieldDecl *FD = *(RD->field_begin()); TransAssert(FD && "Invalid FieldDecl!"); const Type *Ty = FD->getType().getTypePtr(); const RecordType *RT = Ty->getAs(); if (!RT) return true; const RecordDecl *NestedRD = RT->getDecl(); if (NestedRD->getNameAsString() == "") return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->TransformationCounter == ConsumerInstance->ValidInstanceNum) { ConsumerInstance->TheRecordDecl = dyn_cast(RD->getCanonicalDecl()); ConsumerInstance->ReplacingRecordDecl = dyn_cast(NestedRD->getCanonicalDecl()); ConsumerInstance->setQualifierFlags(FD); } return true; } bool SimplifyStructRewriteVisitor::VisitVarDecl(VarDecl *VD) { if (!ConsumerInstance->ConstField && !ConsumerInstance->VolatileField) return true; QualType QT = VD->getType(); const Type *Ty = QT.getTypePtr(); const RecordType *RT = Ty->getAs(); if (!RT) return true; const RecordDecl *RD = RT->getDecl(); if (RD != ConsumerInstance->TheRecordDecl) return true; SourceLocation LocStart = VD->getBeginLoc(); void *LocPtr = LocStart.getPtrEncoding(); if (ConsumerInstance->VisitedVarDeclLocs.count(LocPtr)) return true; ConsumerInstance->VisitedVarDeclLocs.insert(LocPtr); std::string QualStr = ""; if (ConsumerInstance->ConstField && !QT.isConstQualified()) QualStr += "const "; if (ConsumerInstance->VolatileField && !QT.isVolatileQualified()) QualStr += "volatile "; ConsumerInstance->TheRewriter.InsertText(LocStart, QualStr); return true; } bool SimplifyStructRewriteVisitor::VisitRecordDecl(RecordDecl *RD) { RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); if (CanonicalRD != ConsumerInstance->TheRecordDecl) return true; SourceLocation LocStart = RD->getLocation(); void *LocPtr = LocStart.getPtrEncoding(); if (!ConsumerInstance->VisitedLocs.count(LocPtr)) { ConsumerInstance->VisitedLocs.insert(LocPtr); std::string RPName = ConsumerInstance->ReplacingRecordDecl->getNameAsString(); if (RD->getNameAsString() != "") { ConsumerInstance->RewriteHelper->replaceRecordDeclName(RD, RPName); } else { ConsumerInstance->TheRewriter.ReplaceText(LocStart, /*struct*/6, "struct " + RPName); } } if (!RD->isThisDeclarationADefinition()) return true; SourceLocation LBLoc = RD->getBraceRange().getBegin(); SourceLocation RBLoc = RD->getBraceRange().getEnd(); ConsumerInstance->TheRewriter.RemoveText(SourceRange(LBLoc, RBLoc)); return true; } bool SimplifyStructRewriteVisitor::VisitRecordTypeLoc(RecordTypeLoc RTLoc) { const Type *Ty = RTLoc.getTypePtr(); if (Ty->isUnionType()) return true; RecordDecl *RD = RTLoc.getDecl(); RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); if (CanonicalRD != ConsumerInstance->TheRecordDecl) return true; SourceLocation LocStart = RTLoc.getBeginLoc(); void *LocPtr = LocStart.getPtrEncoding(); if (ConsumerInstance->VisitedLocs.count(LocPtr)) return true; ConsumerInstance->VisitedLocs.insert(LocPtr); ConsumerInstance->RewriteHelper->replaceRecordType(RTLoc, ConsumerInstance->ReplacingRecordDecl->getNameAsString()); return true; } bool SimplifyStructRewriteVisitor::VisitMemberExpr(MemberExpr *ME) { ValueDecl *OrigDecl = ME->getMemberDecl(); FieldDecl *FD = dyn_cast(OrigDecl); if (!FD) { // in C++, getMemberDecl returns a CXXMethodDecl. if (TransformationManager::isCXXLangOpt()) return true; TransAssert(0 && "Bad FD!\n"); } RecordDecl *RD = FD->getParent(); if (!RD || (dyn_cast(RD->getCanonicalDecl()) != ConsumerInstance->TheRecordDecl)) return true; const Type *T = FD->getType().getTypePtr(); const RecordType *RT = T->getAs(); TransAssert(RT && "Invalid record type!"); const RecordDecl *ReplacingRD = dyn_cast(RT->getDecl()->getCanonicalDecl()); (void)ReplacingRD; TransAssert((ReplacingRD == ConsumerInstance->ReplacingRecordDecl) && "Unmatched Replacing RD!"); SourceLocation LocEnd = ME->getEndLoc(); if (LocEnd.isMacroID()) { LocEnd = ConsumerInstance->SrcManager->getSpellingLoc(LocEnd); } SourceLocation ArrowPos = Lexer::findLocationAfterToken(LocEnd, tok::arrow, *(ConsumerInstance->SrcManager), ConsumerInstance->Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); SourceLocation PeriodPos = Lexer::findLocationAfterToken(LocEnd, tok::period, *(ConsumerInstance->SrcManager), ConsumerInstance->Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); std::string ES; ConsumerInstance->RewriteHelper->getExprString(ME, ES); // no more MemberExpr upon this ME if (ArrowPos.isInvalid() && PeriodPos.isInvalid()) { SourceLocation StartLoc = ME->getBeginLoc(); size_t Pos; if (ME->isArrow()) { Pos = ES.find("->"); } else { Pos = ES.find("."); } TransAssert((Pos != std::string::npos) && "Cannot find arrow or dot!"); StartLoc = StartLoc.getLocWithOffset(Pos); int Off = ES.length() - Pos; ConsumerInstance->TheRewriter.RemoveText(StartLoc, Off); return true; } SourceLocation StartLoc = ME->getMemberLoc(); const char *StartBuf = ConsumerInstance->SrcManager->getCharacterData(StartLoc); const char *EndBuf; if (ArrowPos.isValid()) { EndBuf = ConsumerInstance->SrcManager->getCharacterData(ArrowPos); EndBuf++; } else { TransAssert(PeriodPos.isValid() && "Bad dot position!"); EndBuf = ConsumerInstance->SrcManager->getCharacterData(PeriodPos); } int Off = EndBuf - StartBuf; ConsumerInstance->TheRewriter.RemoveText(StartLoc, Off); return true; } void SimplifyStruct::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new SimplifyStructCollectionVisitor(this); RewriteVisitor = new SimplifyStructRewriteVisitor(this); } void SimplifyStruct::HandleTranslationUnit(ASTContext &Ctx) { // ISSUE: not well tested on CXX code, so currently disable this pass for CXX if (TransformationManager::isCXXLangOpt()) { ValidInstanceNum = 0; TransError = TransMaxInstanceError; return; } TransAssert(CollectionVisitor && "NULL CollectionVisitor!"); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) { return; } if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); TransAssert(TheRecordDecl && "NULL TheRecordDecl!"); TransAssert(ReplacingRecordDecl && "NULL ReplacingRecordDecl!"); RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyStruct::setQualifierFlags(const FieldDecl *FD) { QualType QT = FD->getType(); if (QT.isConstQualified()) ConstField = true; if (QT.isVolatileQualified()) VolatileField = true; } SimplifyStruct::~SimplifyStruct(void) { delete CollectionVisitor; delete RewriteVisitor; } cvise-2.3.0/clang_delta/SimplifyStruct.h000066400000000000000000000033621402162750500202420ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_STRUCT_H #define SIMPLIFY_STRUCT_H #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class RecordDecl; class FieldDecl; } class SimplifyStructCollectionVisitor; class SimplifyStructRewriteVisitor; class SimplifyStruct : public Transformation { friend class SimplifyStructCollectionVisitor; friend class SimplifyStructRewriteVisitor; public: SimplifyStruct(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), RewriteVisitor(NULL), TheRecordDecl(NULL), ReplacingRecordDecl(NULL), VolatileField(false), ConstField(false) { } ~SimplifyStruct(void); private: typedef llvm::SmallPtrSet LocPtrSet; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void setQualifierFlags(const clang::FieldDecl *FD); LocPtrSet VisitedLocs; LocPtrSet VisitedVarDeclLocs; SimplifyStructCollectionVisitor *CollectionVisitor; SimplifyStructRewriteVisitor *RewriteVisitor; const clang::RecordDecl *TheRecordDecl; const clang::RecordDecl *ReplacingRecordDecl; bool VolatileField; bool ConstField; // Unimplemented SimplifyStruct(void); SimplifyStruct(const SimplifyStruct &); void operator=(const SimplifyStruct &); }; #endif cvise-2.3.0/clang_delta/SimplifyStructUnionDecl.cpp000066400000000000000000000145101402162750500223730ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2017 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "SimplifyStructUnionDecl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "This pass combines the declaration of global vars declared \ as struct/union with the corresponding struct/union \ declaration. \n"; static RegisterTransformation Trans("simplify-struct-union-decl", DescriptionMsg); class SimplifyStructUnionDeclVisitor : public RecursiveASTVisitor { public: explicit SimplifyStructUnionDeclVisitor(SimplifyStructUnionDecl *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitVarDecl(VarDecl *VD); bool VisitFieldDecl(FieldDecl *FD); private: SimplifyStructUnionDecl *ConsumerInstance; }; bool SimplifyStructUnionDeclVisitor::VisitFunctionDecl(FunctionDecl *FD) { const Type *T = FD->getReturnType().getTypePtr(); return ConsumerInstance->handleOneDeclarator(T); } bool SimplifyStructUnionDeclVisitor::VisitVarDecl(VarDecl *VD) { if (ConsumerInstance->CombinedVars.count(VD)) return true; const Type *T = VD->getType().getTypePtr(); return ConsumerInstance->handleOneDeclarator(T); } bool SimplifyStructUnionDeclVisitor::VisitFieldDecl(FieldDecl *FD) { const Type *T = FD->getType().getTypePtr(); return ConsumerInstance->handleOneDeclarator(T); } void SimplifyStructUnionDecl::Initialize(ASTContext &context) { Transformation::Initialize(context); AnalysisVisitor = new SimplifyStructUnionDeclVisitor(this); } bool SimplifyStructUnionDecl::HandleTopLevelDecl(DeclGroupRef DGR) { DeclGroupRef::iterator DI = DGR.begin(); if (isInIncludedFile(*DI)) return true; const RecordDecl *RD = dyn_cast(*DI); if (RD) { addOneRecordDecl(RD, DGR); return true; } VarDecl *VD = dyn_cast(*DI); if (!VD) return true; const Type *T = VD->getType().getTypePtr(); RD = getBaseRecordDecl(T); if (!RD) return true; const Decl *CanonicalD = RD->getCanonicalDecl(); void *DGRPointer = RecordDeclToDeclGroup[CanonicalD]; if (!DGRPointer) return true; ValidInstanceNum++; if (ValidInstanceNum != TransformationCounter) return true; TheRecordDecl = dyn_cast(CanonicalD); TheDeclGroupRefs.push_back(DGRPointer); TheDeclGroupRefs.push_back(DGR.getAsOpaquePtr()); for (DeclGroupRef::iterator I = DGR.begin(), E = DGR.end(); I != E; ++I) { VarDecl *VD = dyn_cast(*I); TransAssert(VD && "Bad VarDecl!"); CombinedVars.insert(VD); } DeclGroupRef DefDGR = DeclGroupRef::getFromOpaquePtr(DGRPointer); for (DeclGroupRef::iterator I = DefDGR.begin(), E = DefDGR.end(); I != E; ++I) { VarDecl *VD = dyn_cast(*I); if (VD) CombinedVars.insert(VD); } return true; } void SimplifyStructUnionDecl::HandleTranslationUnit(ASTContext &Ctx) { if (QueryInstanceOnly) { return; } if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(AnalysisVisitor && "NULL AnalysisVisitor!"); TransAssert(TheRecordDecl && "NULL RecordDecl!"); AnalysisVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); doCombination(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void SimplifyStructUnionDecl::doCombination(void) { TransAssert(TheDeclGroupRefs.size() == 2); void *P2 = TheDeclGroupRefs.pop_back_val(); void *P1 = TheDeclGroupRefs.pop_back_val(); DeclGroupRef FirstDGR = DeclGroupRef::getFromOpaquePtr(P1); DeclGroupRef SecondDGR = DeclGroupRef::getFromOpaquePtr(P2); SourceLocation EndLoc = RewriteHelper->getDeclGroupRefEndLoc(FirstDGR); std::string DStr; RewriteHelper->getDeclGroupStrAndRemove(SecondDGR, DStr); // it's a single RecordDecl if (FirstDGR.isSingleDecl()) TheRewriter.InsertText(EndLoc, DStr, /*InsertAfter=*/false); else TheRewriter.InsertText(EndLoc, ", " + DStr, /*InsertAfter=*/false); if (isSafeToRemoveName()) { SourceLocation NameLocStart = TheRecordDecl->getLocation(); std::string Name = TheRecordDecl->getNameAsString(); TheRewriter.RemoveText(NameLocStart, Name.size()); } } bool SimplifyStructUnionDecl::isSafeToRemoveName(void) { if (!SafeToRemoveName) return false; const RecordDecl *RD = dyn_cast(TheRecordDecl->getCanonicalDecl()); RecordDecl::redecl_iterator I = RD->redecls_begin(); RecordDecl::redecl_iterator E = RD->redecls_end(); ++I; return (I == E); } void SimplifyStructUnionDecl::addOneRecordDecl(const RecordDecl *RD, DeclGroupRef DGR) { const Decl *CanonicalD = RD->getCanonicalDecl(); const RecordDecl *RDDef = RD->getDefinition(); if (!RDDef || (RD != RDDef)) return; if (!RecordDeclToDeclGroup[CanonicalD]) RecordDeclToDeclGroup[CanonicalD] = (DGR.getAsOpaquePtr()); } const RecordDecl *SimplifyStructUnionDecl::getBaseRecordDecl(const Type *T) { const ArrayType *ArrayTy = dyn_cast(T); if (ArrayTy) T = getArrayBaseElemType(ArrayTy); if (T->isPointerType()) T = getBasePointerElemType(T); const RecordType *RT = NULL; if (T->isUnionType()) RT = T->getAsUnionType(); else if (T->isStructureType()) RT = T->getAsStructureType(); else return NULL; return RT->getDecl(); } bool SimplifyStructUnionDecl::handleOneDeclarator(const Type *Ty) { const RecordDecl *RD = getBaseRecordDecl(Ty); if (!RD) return true; const RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); if (CanonicalRD == TheRecordDecl) { SafeToRemoveName = false; } return SafeToRemoveName; } SimplifyStructUnionDecl::~SimplifyStructUnionDecl(void) { delete AnalysisVisitor; } cvise-2.3.0/clang_delta/SimplifyStructUnionDecl.h000066400000000000000000000040631402162750500220420ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef SIMPLIFY_STRUCT_UNION_DECL_H #define SIMPLIFY_STRUCT_UNION_DECL_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class RecordDecl; class Type; class VarDecl; } class SimplifyStructUnionDeclVisitor; class SimplifyStructUnionDecl : public Transformation { friend class SimplifyStructUnionDeclVisitor; public: SimplifyStructUnionDecl(const char *TransName, const char *Desc) : Transformation(TransName, Desc), AnalysisVisitor(NULL), TheRecordDecl(NULL), SafeToRemoveName(true) { } ~SimplifyStructUnionDecl(void); private: typedef llvm::SmallPtrSet VarDeclSet; typedef llvm::DenseMap RecordDeclToDeclGroupMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addOneRecordDecl(const clang::RecordDecl *RD, clang::DeclGroupRef DGR); void doCombination(); bool handleOneDeclarator(const clang::Type *Ty); const clang::RecordDecl *getBaseRecordDecl(const clang::Type *Ty); bool isSafeToRemoveName(void); RecordDeclToDeclGroupMap RecordDeclToDeclGroup; llvm::SmallVector TheDeclGroupRefs; VarDeclSet CombinedVars; SimplifyStructUnionDeclVisitor *AnalysisVisitor; const clang::RecordDecl *TheRecordDecl; bool SafeToRemoveName; // Unimplemented SimplifyStructUnionDecl(void); SimplifyStructUnionDecl(const SimplifyStructUnionDecl &); void operator=(const SimplifyStructUnionDecl &); }; #endif cvise-2.3.0/clang_delta/TemplateArgToInt.cpp000066400000000000000000000267461402162750500207720ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2017, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "TemplateArgToInt.h" #include "clang/Lex/Lexer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonTemplateArgumentVisitor.h" using namespace clang; using namespace clang_delta_common_visitor; static const char *DescriptionMsg = "This pass replaces a template argument in an instantiation with \ int if the argument: \n\ * is type of CXXRecord; \n\ * the corresponding template parameter T is not used as T::x, \n\ nor template class : T { ... };\n\ For example, from:\n\ struct S {};\n\ template struct C {};\n\ C c;\n\ to:\n\ struct S {};\n\ template struct C {};\n\ C c;\n\ "; static RegisterTransformation Trans("template-arg-to-int", DescriptionMsg); class TemplateArgToIntASTVisitor : public RecursiveASTVisitor { public: explicit TemplateArgToIntASTVisitor( TemplateArgToInt *Instance) : ConsumerInstance(Instance) { } bool VisitClassTemplateDecl(ClassTemplateDecl *D); bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); private: TemplateArgToInt *ConsumerInstance; }; class TemplateArgToIntArgCollector : public CommonTemplateArgumentVisitor { public: explicit TemplateArgToIntArgCollector(TemplateArgToInt *Instance) : CommonTemplateArgumentVisitor(Instance) { } }; typedef llvm::SmallPtrSet TemplateParameterSet; // rule out cases like: //template struct S { typedef T1 type; }; // struct S1 { void foo() {} }; // struct S2 { // typedef S::type type; // S::type s1; // type s2; // void bar() { s1.foo(); s2.foo(); } // }; class TemplateGlobalInvalidParameterVisitor : public RecursiveASTVisitor { public: explicit TemplateGlobalInvalidParameterVisitor( TemplateArgToInt *Instance) : ConsumerInstance(Instance) { } ~TemplateGlobalInvalidParameterVisitor() { }; bool VisitMemberExpr(MemberExpr *ME); bool VisitCXXRecordDecl(CXXRecordDecl *D); private: TemplateArgToInt *ConsumerInstance; }; bool TemplateGlobalInvalidParameterVisitor::VisitMemberExpr(MemberExpr *ME) { const Expr *Base = ME->getBase(); if (dyn_cast(Base)) return true; const Type *Ty = Base->getType().getTypePtr(); ConsumerInstance->handleOneType(Ty); return true; } bool TemplateGlobalInvalidParameterVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { if (!D->isCompleteDefinition()) return true; for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); ConsumerInstance->handleOneType(Ty); } return true; } class TemplateInvalidParameterVisitor : public RecursiveASTVisitor { public: TemplateInvalidParameterVisitor(TemplateParameterSet &Params, TemplateArgToInt *Instance) : Parameters(Params), ConsumerInstance(Instance) { } ~TemplateInvalidParameterVisitor() { }; bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc Loc); bool VisitCXXRecordDecl(CXXRecordDecl *D); private: TemplateParameterSet &Parameters; TemplateArgToInt *ConsumerInstance; }; bool TemplateInvalidParameterVisitor::VisitTemplateTypeParmTypeLoc( TemplateTypeParmTypeLoc Loc) { const NamedDecl *ND = Loc.getDecl(); if (ConsumerInstance->isBeforeColonColon(Loc)) Parameters.insert(ND); return true; } bool TemplateInvalidParameterVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { if (!D->isCompleteDefinition()) return true; for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const TemplateTypeParmType *ParmTy = dyn_cast(Ty); if (!ParmTy) continue; const TemplateTypeParmDecl *ParmD = ParmTy->getDecl(); Parameters.insert(ParmD); } return true; } bool TemplateArgToIntASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneTemplateDecl(D); return true; } bool TemplateArgToIntASTVisitor::VisitFunctionTemplateDecl( FunctionTemplateDecl *D) { if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneTemplateDecl(D); return true; } void TemplateArgToInt::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new TemplateArgToIntASTVisitor(this); ArgCollector = new TemplateArgToIntArgCollector(this); GlobalParamFilter = new TemplateGlobalInvalidParameterVisitor(this); } void TemplateArgToInt::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); GlobalParamFilter->TraverseDecl(Ctx.getTranslationUnitDecl()); ArgCollector->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); rewriteTemplateArgument(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void TemplateArgToInt::collectInvalidParamIdx( const TemplateDecl *D, TemplateParameterIdxSet &InvalidParamIdx) { TemplateParameterSet InvalidParams; NamedDecl *ND = D->getTemplatedDecl(); TemplateInvalidParameterVisitor ParameterVisitor(InvalidParams, this); ParameterVisitor.TraverseDecl(ND); TemplateParameterList *TPList = D->getTemplateParameters(); unsigned Idx = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ParamND = (*I); ParamToTemplateDecl[ParamND] = D; if (InvalidParams.count(ParamND)) { TransAssert(!InvalidParamIdx.count(Idx) && "Duplicate Index!"); InvalidParamIdx.insert(Idx); } Idx++; } } void TemplateArgToInt::handleOneTemplateDecl(const TemplateDecl *D) { TemplateParameterIdxSet *InvalidIdx = new TemplateParameterIdxSet(); collectInvalidParamIdx(D, *InvalidIdx); TransAssert(!DeclToParamIdx[D] && "Duplicate TemplateDecl!"); DeclToParamIdx[dyn_cast(D->getCanonicalDecl())] = InvalidIdx; } void TemplateArgToInt::handleOneTemplateArgumentLoc( const TemplateArgumentLoc &ArgLoc) { if (ArgLoc.getLocation().isInvalid() || isInIncludedFile(ArgLoc.getLocation())) return; const TemplateArgument &Arg = ArgLoc.getArgument(); if (Arg.getKind() != TemplateArgument::Type) return; const Type *Ty = Arg.getAsType().getTypePtr(); if (!Ty->getAsCXXRecordDecl() && !Ty->getPointeeCXXRecordDecl()) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) TheTypeSourceInfo = ArgLoc.getTypeSourceInfo(); } void TemplateArgToInt::handleTemplateArgumentLocs( const TemplateDecl *D, const TemplateArgumentLoc *TAL, unsigned NumArgs) { TransAssert(D && "NULL TemplateDecl!"); if (!TAL) return; TemplateParameterIdxSet *InvalidIdx = DeclToParamIdx[dyn_cast(D->getCanonicalDecl())]; if (!InvalidIdx) return; for (unsigned I = 0; I < NumArgs; ++I) { if (!InvalidIdx->count(I)) handleOneTemplateArgumentLoc(TAL[I]); } } void TemplateArgToInt::handleTemplateSpecializationTypeLoc( const TemplateSpecializationTypeLoc &TLoc) { const Type *Ty = TLoc.getTypePtr(); const TemplateSpecializationType *TST = Ty->getAs(); TemplateName TplName = TST->getTemplateName(); const TemplateDecl *TplD = TplName.getAsTemplateDecl(); TemplateParameterIdxSet *InvalidIdx = DeclToParamIdx[dyn_cast(TplD->getCanonicalDecl())]; if (!InvalidIdx) return; for (unsigned I = 0; I < TLoc.getNumArgs(); ++I) { if (!InvalidIdx->count(I)) handleOneTemplateArgumentLoc(TLoc.getArgLoc(I)); } } void TemplateArgToInt::rewriteTemplateArgument() { TransAssert(TheTypeSourceInfo && "NULL TheTypeSourceInfo"); SourceRange Range = TheTypeSourceInfo->getTypeLoc().getSourceRange(); TheRewriter.ReplaceText(Range, "int"); } const SubstTemplateTypeParmType * TemplateArgToInt::getSubstTemplateTypeParmType(const Type *Ty) { Type::TypeClass TC = Ty->getTypeClass(); switch (TC) { case Type::Elaborated: { const ElaboratedType *ETy = dyn_cast(Ty); const Type *NamedT = ETy->getNamedType().getTypePtr(); return getSubstTemplateTypeParmType(NamedT); } case Type::Typedef: { const TypedefType *TdefTy = dyn_cast(Ty); const TypedefNameDecl *TdefD = TdefTy->getDecl(); const Type *UnderlyingTy = TdefD->getUnderlyingType().getTypePtr(); return getSubstTemplateTypeParmType(UnderlyingTy); } case Type::SubstTemplateTypeParm: { return dyn_cast(Ty); } default: return NULL; } return NULL; } void TemplateArgToInt::handleOneType(const Type *Ty) { if (Ty->isPointerType() || Ty->isReferenceType()) Ty = getBasePointerElemType(Ty); const SubstTemplateTypeParmType *SubstType = getSubstTemplateTypeParmType(Ty); if (!SubstType) return; const TemplateTypeParmType *ParmType = SubstType->getReplacedParameter(); TemplateTypeParmDecl *ParmDecl = ParmType->getDecl(); TransAssert(ParmDecl && "Invalid ParmDecl!"); const TemplateDecl *TmplD = ParamToTemplateDecl[ParmDecl]; if (TmplD == NULL) { const DeclContext *Ctx = ParmDecl->getDeclContext(); TransAssert(Ctx && "NULL Ctx!"); const ClassTemplateSpecializationDecl *Spec = dyn_cast(Ctx); TransAssert(Spec && "Not a ClassTemplateSpecializationDecl!"); TmplD = Spec->getSpecializedTemplate(); } if (const ClassTemplateDecl *ClassTmplD = dyn_cast(TmplD)) { if (!ClassTmplD->getTemplatedDecl()->hasDefinition()) return; } if (const FunctionTemplateDecl *FuncTmplD = dyn_cast(TmplD)) { if (!FuncTmplD->getTemplatedDecl()->getDefinition()) return; } TransAssert(TmplD && "NULL TemplateDecl!"); TemplateParameterIdxSet *InvalidIdx = DeclToParamIdx[dyn_cast(TmplD->getCanonicalDecl())]; TransAssert(InvalidIdx && "NULL InvalidIdx!"); InvalidIdx->insert(ParmType->getIndex()); } TemplateArgToInt::~TemplateArgToInt() { for (TemplateDeclToParamIdxMap::iterator I = DeclToParamIdx.begin(), E = DeclToParamIdx.end(); I != E; ++I) { delete (*I).second; } delete CollectionVisitor; delete ArgCollector; delete GlobalParamFilter; } cvise-2.3.0/clang_delta/TemplateArgToInt.h000066400000000000000000000066231402162750500204270ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef TEMPLATE_ARG_TO_INT_H #define TEMPLATE_ARG_TO_INT_H #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class TemplateDecl; class NamedDecl; class TemplateArgumentLoc; class TemplateSpecializationTypeLoc; class TypeSourceInfo; class Type; class SubstTemplateTypeParmType; } class TemplateArgToIntASTVisitor; class TemplateArgToIntArgCollector; class TemplateGlobalInvalidParameterVisitor; namespace clang_delta_common_visitor { template class CommonTemplateArgumentVisitor; } class TemplateArgToInt : public Transformation { friend class TemplateArgToIntASTVisitor; friend class TemplateArgToIntArgCollector; friend class TemplateInvalidParameterVisitor; friend class TemplateGlobalInvalidParameterVisitor; friend class clang_delta_common_visitor:: CommonTemplateArgumentVisitor; public: TemplateArgToInt(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), ArgCollector(NULL), GlobalParamFilter(NULL) {} ~TemplateArgToInt(); private: typedef llvm::SmallPtrSet TemplateDeclSet; typedef llvm::SmallPtrSet TemplateParameterSet; typedef llvm::SmallSet TemplateParameterIdxSet; typedef llvm::DenseMap TemplateDeclToParamIdxMap; typedef llvm::DenseMap ParameterToTemplateDeclMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void collectInvalidParamIdx(const clang::TemplateDecl *D, TemplateParameterIdxSet &InvalidParamIdx); void handleOneTemplateDecl(const clang::TemplateDecl *D); void handleTemplateArgumentLocs(const clang::TemplateDecl *D, const clang::TemplateArgumentLoc *TAL, unsigned NumArgs); void handleOneTemplateArgumentLoc(const clang::TemplateArgumentLoc &ArgLoc); void handleTemplateSpecializationTypeLoc( const clang::TemplateSpecializationTypeLoc &TLoc); void handleOneType(const clang::Type *Ty); const clang::SubstTemplateTypeParmType * getSubstTemplateTypeParmType(const clang::Type *Ty); void rewriteTemplateArgument(); TemplateDeclToParamIdxMap DeclToParamIdx; ParameterToTemplateDeclMap ParamToTemplateDecl; TemplateArgToIntASTVisitor *CollectionVisitor; TemplateArgToIntArgCollector *ArgCollector; TemplateGlobalInvalidParameterVisitor *GlobalParamFilter; clang::TypeSourceInfo *TheTypeSourceInfo; // Unimplemented TemplateArgToInt(); TemplateArgToInt(const TemplateArgToInt &); void operator=(const TemplateArgToInt &); }; #endif cvise-2.3.0/clang_delta/TemplateNonTypeArgToInt.cpp000066400000000000000000000162111402162750500222710ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016, 2017, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "TemplateNonTypeArgToInt.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include "CommonTemplateArgumentVisitor.h" using namespace clang; using namespace clang_delta_common_visitor; static const char *DescriptionMsg = "This pass tries to replace a template non-type argument \ wth an integer (if its type is compatible) \n"; static RegisterTransformation Trans("template-non-type-arg-to-int", DescriptionMsg); class TemplateNonTypeArgToIntArgCollector : public RecursiveASTVisitor { public: explicit TemplateNonTypeArgToIntArgCollector( TemplateNonTypeArgToInt *Instance) : ConsumerInstance(Instance) { } bool VisitClassTemplateDecl(ClassTemplateDecl *D); bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); private: TemplateNonTypeArgToInt *ConsumerInstance; }; bool TemplateNonTypeArgToIntArgCollector::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneTemplateDecl(D); return true; } bool TemplateNonTypeArgToIntArgCollector::VisitFunctionTemplateDecl( FunctionTemplateDecl *D) { if (D->isThisDeclarationADefinition()) ConsumerInstance->handleOneTemplateDecl(D); return true; } class TemplateNonTypeArgToIntASTVisitor : public CommonTemplateArgumentVisitor { public: explicit TemplateNonTypeArgToIntASTVisitor( TemplateNonTypeArgToInt *Instance) : CommonTemplateArgumentVisitor(Instance) { } }; void TemplateNonTypeArgToInt::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new TemplateNonTypeArgToIntASTVisitor(this); ArgCollector = new TemplateNonTypeArgToIntArgCollector(this); } void TemplateNonTypeArgToInt::HandleTranslationUnit(ASTContext &Ctx) { if (TransformationManager::isCLangOpt() || TransformationManager::isOpenCLLangOpt()) { ValidInstanceNum = 0; } else { ArgCollector->TraverseDecl(Ctx.getTranslationUnitDecl()); CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl()); } if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); if (TheExpr) { RewriteHelper->replaceExpr(TheExpr, IntString); } else if (TheValueDecl) { RewriteHelper->replaceValueDecl(TheValueDecl, "int " + TheValueDecl->getNameAsString()); } else { TransAssert(0 && "No valid targets!"); } if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool TemplateNonTypeArgToInt::isValidTemplateArgument( const TemplateArgument &Arg) { TemplateArgument::ArgKind K = Arg.getKind(); switch (K) { case TemplateArgument::Declaration: { return true; } case TemplateArgument::Expression: { const Expr *E = Arg.getAsExpr()->IgnoreParenCasts(); if (dyn_cast(E) || dyn_cast(E)) return false; if (const UnaryOperator *UO = dyn_cast(E)) { UnaryOperator::Opcode Op = UO->getOpcode(); if((Op == UO_Minus) || (Op == UO_Plus)) return false; } return true; } default: TransAssert(0 && "Unreachable code!"); return false; } TransAssert(0 && "Unreachable code!"); return false; } void TemplateNonTypeArgToInt::handleOneTemplateArgumentLoc( const TemplateArgumentLoc &ArgLoc) { if (ArgLoc.getLocation().isInvalid()) return; const TemplateArgument &Arg = ArgLoc.getArgument(); if (!isValidTemplateArgument(Arg)) return; ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { TheExpr = ArgLoc.getLocInfo().getAsExpr(); Expr::EvalResult Result; if (!TheExpr->isValueDependent() && TheExpr->EvaluateAsInt(Result, *Context)) { llvm::APSInt IVal = Result.Val.getInt(); IntString = IVal.toString(10); } } } void TemplateNonTypeArgToInt::handleTemplateArgumentLocs( const TemplateDecl *D, const TemplateArgumentLoc *TAL, unsigned NumArgs) { TransAssert(D && "NULL TemplateDecl!"); if (!TAL) return; TemplateParameterIdxSet *ValidIdx = DeclToParamIdx[dyn_cast(D->getCanonicalDecl())]; if (!ValidIdx) return; for (unsigned I = 0; I < NumArgs; ++I) { if (ValidIdx->count(I)) handleOneTemplateArgumentLoc(TAL[I]); } } void TemplateNonTypeArgToInt::handleTemplateSpecializationTypeLoc( const TemplateSpecializationTypeLoc &TLoc) { const Type *Ty = TLoc.getTypePtr(); const TemplateSpecializationType *TST = Ty->getAs(); TemplateName TplName = TST->getTemplateName(); const TemplateDecl *TplD = TplName.getAsTemplateDecl(); TemplateParameterIdxSet *ValidIdx = DeclToParamIdx[dyn_cast(TplD->getCanonicalDecl())]; if (!ValidIdx) return; for (unsigned I = 0; I < TLoc.getNumArgs(); ++I) { if (ValidIdx->count(I)) handleOneTemplateArgumentLoc(TLoc.getArgLoc(I)); } } bool TemplateNonTypeArgToInt::isValidParameter(const NamedDecl *ND) { const NonTypeTemplateParmDecl *NonTypeD = dyn_cast(ND); if (!NonTypeD) return false; // To avoid something like replacing int with int. if (NonTypeD->getType().getAsString() == "int") return false; const Type *Ty = NonTypeD->getType().getTypePtr(); return Ty->isIntegerType(); } void TemplateNonTypeArgToInt::handleOneTemplateDecl(const TemplateDecl *D) { if (isInIncludedFile(D)) return; TemplateParameterIdxSet *ValidParamIdx = new TemplateParameterIdxSet(); TemplateParameterList *TPList = D->getTemplateParameters(); unsigned Idx = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ParamND = (*I); if (isValidParameter(ParamND)) { ValidParamIdx->insert(Idx); if (const ValueDecl* ValD = dyn_cast(ParamND)) { ++ValidInstanceNum; if (ValidInstanceNum == TransformationCounter) TheValueDecl = ValD; } } Idx++; } TransAssert(!DeclToParamIdx[D] && "Duplicate TemplateDecl!"); DeclToParamIdx[dyn_cast(D->getCanonicalDecl())] = ValidParamIdx; } TemplateNonTypeArgToInt::~TemplateNonTypeArgToInt() { delete CollectionVisitor; delete ArgCollector; } cvise-2.3.0/clang_delta/TemplateNonTypeArgToInt.h000066400000000000000000000055011402162750500217360ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef TEMPLATE_NON_TYPE_ARG_TO_INT_H #define TEMPLATE_NON_TYPE_ARG_TO_INT_H #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/DenseMap.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class Expr; class TemplateDecl; class TemplateArgumentLoc; class TemplateArgument; class TemplateSpecializationTypeLoc; class NamedDecl; class ValueDecl; } namespace clang_delta_common_visitor { template class CommonTemplateArgumentVisitor; } class TemplateNonTypeArgToIntASTVisitor; class TemplateNonTypeArgToIntArgCollector; class TemplateNonTypeArgToInt : public Transformation { friend class TemplateNonTypeArgToIntASTVisitor; friend class clang_delta_common_visitor::CommonTemplateArgumentVisitor ; friend class TemplateNonTypeArgToIntArgCollector; public: TemplateNonTypeArgToInt(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), ArgCollector(NULL), TheExpr(NULL), TheValueDecl(NULL), IntString("1") {} ~TemplateNonTypeArgToInt(); private: typedef llvm::SmallSet TemplateParameterIdxSet; typedef llvm::DenseMap TemplateDeclToParamIdxMap; virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void handleOneTemplateDecl(const clang::TemplateDecl *D); bool isValidParameter(const clang::NamedDecl *ND); void handleTemplateArgumentLocs(const clang::TemplateDecl *D, const clang::TemplateArgumentLoc *TAL, unsigned NumArgs); void handleOneTemplateArgumentLoc(const clang::TemplateArgumentLoc &ArgLoc); void handleTemplateSpecializationTypeLoc( const clang::TemplateSpecializationTypeLoc &TLoc); bool isValidTemplateArgument(const clang::TemplateArgument &Arg); TemplateDeclToParamIdxMap DeclToParamIdx; TemplateNonTypeArgToIntASTVisitor *CollectionVisitor; TemplateNonTypeArgToIntArgCollector *ArgCollector; clang::Expr *TheExpr; const clang::ValueDecl *TheValueDecl; std::string IntString; // Unimplemented TemplateNonTypeArgToInt(); TemplateNonTypeArgToInt(const TemplateNonTypeArgToInt &); void operator=(const TemplateNonTypeArgToInt &); }; #endif cvise-2.3.0/clang_delta/Transformation.cpp000066400000000000000000001010461402162750500206000ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "Transformation.h" #include #include #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" using namespace std; using namespace clang; class TransNameQueryVisitor : public RecursiveASTVisitor { public: TransNameQueryVisitor(TransNameQueryWrap *Instance, const std::string &Prefix) : WrapInstance(Instance), NamePrefix(Prefix) { } bool VisitVarDecl(VarDecl *VD); private: TransNameQueryWrap *WrapInstance; const std::string NamePrefix; }; bool TransNameQueryVisitor::VisitVarDecl(VarDecl *VD) { std::string Name = VD->getNameAsString(); size_t Sz = NamePrefix.size(); if (Name.compare(0, Sz, NamePrefix)) return true; std::string PostfixStr = Name.substr(Sz); TransAssert((PostfixStr.size() > 0) && "Bad trans tmp name!"); std::stringstream TmpSS(PostfixStr); unsigned int PostfixV; if (!(TmpSS >> PostfixV)) TransAssert(0 && "Non-integer trans tmp name!"); if (PostfixV > WrapInstance->MaxPostfix) WrapInstance->MaxPostfix = PostfixV; return true; } TransNameQueryWrap::TransNameQueryWrap(const std::string &Prefix) : NamePrefix(Prefix), MaxPostfix(0) { NameQueryVisitor = new TransNameQueryVisitor(this, Prefix); } TransNameQueryWrap::~TransNameQueryWrap(void) { delete NameQueryVisitor; } bool TransNameQueryWrap::TraverseDecl(Decl *D) { return NameQueryVisitor->TraverseDecl(D); } void Transformation::Initialize(ASTContext &context) { Context = &context; SrcManager = &Context->getSourceManager(); TheRewriter.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); RewriteHelper = RewriteUtils::GetInstance(&TheRewriter); } void Transformation::outputTransformedSource(llvm::raw_ostream &OutStream) { FileID MainFileID = SrcManager->getMainFileID(); const RewriteBuffer *RWBuf = TheRewriter.getRewriteBufferFor(MainFileID); // RWBuf is non-empty upon any rewrites TransAssert(RWBuf && "Empty RewriteBuffer!"); OutStream << std::string(RWBuf->begin(), RWBuf->end()); OutStream.flush(); } void Transformation::outputOriginalSource(llvm::raw_ostream &OutStream) { FileID MainFileID = SrcManager->getMainFileID(); #if LLVM_VERSION_MAJOR >= 12 llvm::Optional MainBuf = SrcManager->getBufferOrNone(MainFileID); #else const llvm::MemoryBuffer *MainBuf = SrcManager->getBuffer(MainFileID); #endif TransAssert(MainBuf && "Empty MainBuf!"); OutStream << MainBuf->getBufferStart(); OutStream.flush(); } void Transformation::getTransErrorMsg(std::string &ErrorMsg) { if (TransError == TransSuccess) { ErrorMsg = ""; } else if (TransError == TransInternalError) { ErrorMsg = "Internal transformation error!"; } else if (TransError == TransMaxInstanceError) { ErrorMsg = "The counter value exceeded the number of transformation instances!"; } else if (TransError == TransMaxVarsError) { ErrorMsg = "Too many variables!"; } else if (TransError == TransMaxClassesError) { ErrorMsg = "Too many classes!"; } else if (TransError == TransNoValidVarsError) { ErrorMsg = "No variables need to be renamed!"; } else if (TransError == TransNoValidFunsError) { ErrorMsg = "No valid function declarations exist!"; } else if (TransError == TransNoValidParamsError) { ErrorMsg = "No valid parameters declarations exist!"; } else if (TransError == TransNoTextModificationError) { ErrorMsg = "No modification to the transformed program!"; } else if (TransError == TransToCounterTooBigError) { ErrorMsg = "The to-counter value exceeded the number of transformation instances!"; } else { TransAssert(0 && "Unknown transformation error!"); } } bool Transformation::checkCounterValidity() { if (TransformationCounter > ValidInstanceNum) { if (WarnOnCounterOutOfBounds) { TransformationCounter = ValidInstanceNum; cerr << "Warning: number of transformation instances exceeded" << endl; } else { TransError = TransMaxInstanceError; return false; } } if (ToCounter > ValidInstanceNum) { if (WarnOnCounterOutOfBounds) { ToCounter = ValidInstanceNum; cerr << "Warning: number of transformation instances exceeded" << endl; } else { TransError = TransMaxInstanceError; return false; } } return true; } const Expr * Transformation::ignoreSubscriptExprParenCasts(const Expr *E) { const Expr *NewE = E->IgnoreParenCasts(); const ArraySubscriptExpr *ASE; while (true) { ASE = dyn_cast(NewE); if (!ASE) break; NewE = ASE->getBase()->IgnoreParenCasts(); } TransAssert(NewE && "NULL NewE!"); return NewE; } const Expr *Transformation::getInitExprByIndex(IndexVector &Idxs, const InitListExpr *ILE) { const InitListExpr *SubILE = ILE; const Expr *Exp = NULL; unsigned int Count = 0; for (IndexVector::const_reverse_iterator I = Idxs.rbegin(), E = Idxs.rend(); I != E; ++I) { Count++; unsigned int Idx; const Type *T = SubILE->getType().getTypePtr(); if (T->isUnionType()) Idx = 0; else Idx = (*I); // Incomplete initialization list if (Idx >= SubILE->getNumInits()) return NULL; Exp = SubILE->getInit(Idx); TransAssert(Exp && "NULL Exp!"); SubILE = dyn_cast(Exp); if (!SubILE) break; } TransAssert(Exp && "Exp cannot be NULL"); // If array-to-pointer-decay happens, the Count can // be different from the size of Idxs. In this case, // we just return NULL. if (Count == Idxs.size()) return Exp; else return NULL; } const Expr *Transformation::getArrayBaseExprAndIdxs( const ArraySubscriptExpr *ASE, IndexVector &Idxs) { const Expr *BaseE = NULL; while (ASE) { const Expr *IdxE = ASE->getIdx(); unsigned int Idx = 0; Expr::EvalResult Result; if (IdxE && IdxE->EvaluateAsInt(Result, *Context)) { // this will truncate a possible uint64 value to uint32 value llvm::APSInt IVal = Result.Val.getInt(); Idx = (unsigned int)(*IVal.getRawData()); } BaseE = ASE->getBase()->IgnoreParenCasts(); ASE = dyn_cast(BaseE); Idxs.push_back(Idx); } return BaseE; } const Expr *Transformation::getInitExprFromBase(const Expr *BaseE, IndexVector &Idxs) { TransAssert(BaseE && "Bad Array Base Expression!"); const DeclRefExpr *DRE = dyn_cast(BaseE); if (!DRE) return NULL; const ValueDecl *OrigDecl = DRE->getDecl(); const VarDecl *VD = dyn_cast(OrigDecl); TransAssert(VD && "Bad VarDecl!"); const Type * Ty = VD->getType().getTypePtr(); if (Ty->isPointerType()) return NULL; const Expr *InitE = VD->getAnyInitializer(); if (!InitE) return NULL; // We don't have routine for CXXConstructExpr if (dyn_cast(InitE)) return NULL; const InitListExpr *ILE = dyn_cast(InitE); // not always the case we will have an InitListExpr, e.g., // RHS is a struct, or dereferencing a struct pointer, etc if (!ILE) return NULL; return getInitExprByIndex(Idxs, ILE); } const Expr *Transformation::getArraySubscriptElem( const ArraySubscriptExpr *ASE) { IndexVector ArrayDims; const Expr *BaseE = getArrayBaseExprAndIdxs(ASE, ArrayDims); return getInitExprFromBase(BaseE, ArrayDims); } const Expr *Transformation::getMemberExprBaseExprAndIdxs( const MemberExpr *ME, IndexVector &Idxs) { const Expr *BaseE = NULL; while (ME) { ValueDecl *VD = ME->getMemberDecl(); FieldDecl *FD = dyn_cast(VD); if (!FD) return NULL; unsigned int Idx = FD->getFieldIndex(); Idxs.push_back(Idx); BaseE = ME->getBase()->IgnoreParenCasts(); const ArraySubscriptExpr *ASE = dyn_cast(BaseE); if (ASE) { BaseE = getArrayBaseExprAndIdxs(ASE, Idxs); if (!BaseE) return NULL; } ME = dyn_cast(BaseE); } return BaseE; } bool Transformation::isCXXMemberExpr(const MemberExpr *ME) { const ValueDecl *VD = ME->getMemberDecl(); const FieldDecl *FD = dyn_cast(VD); // VD can be either CXXMethodDecl, EnumConstantDecl or // VarDecl (static data member) if (!FD) return true; const CXXRecordDecl *CXXRD = dyn_cast(FD->getParent()); if (!CXXRD) return false; return !(CXXRD->isCLike()); } const Expr *Transformation::getMemberExprElem(const MemberExpr *ME) { if (isCXXMemberExpr(ME)) return NULL; IndexVector Idxs; const Expr *BaseE = getMemberExprBaseExprAndIdxs(ME, Idxs); if (!BaseE) return NULL; return getInitExprFromBase(BaseE, Idxs); } unsigned int Transformation::getArrayDimension(const ArrayType *ArrayTy) { unsigned int Dim = 1; const Type *ArrayElemTy = ArrayTy->getElementType().getTypePtr(); while (ArrayElemTy->isArrayType()) { const ArrayType *AT = dyn_cast(ArrayElemTy); ArrayElemTy = AT->getElementType().getTypePtr(); Dim++; } return Dim; } unsigned int Transformation::getArrayDimensionAndTypes( const ArrayType *ArrayTy, ArraySubTypeVector &TyVec) { unsigned int Dim = 1; const Type *ArrayElemTy = ArrayTy->getElementType().getTypePtr(); TyVec.push_back(ArrayTy); while (ArrayElemTy->isArrayType()) { const ArrayType *AT = dyn_cast(ArrayElemTy); TyVec.push_back(AT); ArrayElemTy = AT->getElementType().getTypePtr(); Dim++; } return Dim; } const Type *Transformation::getArrayBaseElemType(const ArrayType *ArrayTy) { return ArrayTy->getBaseElementTypeUnsafe(); } unsigned int Transformation::getConstArraySize( const ConstantArrayType *CstArrayTy) { unsigned int Sz; llvm::APInt Result = CstArrayTy->getSize(); llvm::SmallString<8> IntStr; Result.toStringUnsigned(IntStr); std::stringstream TmpSS(IntStr.str().str()); if (!(TmpSS >> Sz)) { TransAssert(0 && "Non-integer value!"); } return Sz; } // This is a more complete implementation to deal with mixed // array and structs/unions const Expr *Transformation::getBaseExprAndIdxs(const Expr *E, IndexVector &Idxs) { const Expr *BaseE = NULL; while (E) { E = E->IgnoreParenCasts(); BaseE = E; Expr::StmtClass SC = E->getStmtClass(); if (SC == Expr::MemberExprClass) { const MemberExpr *ME = dyn_cast(E); ValueDecl *VD = ME->getMemberDecl(); FieldDecl *FD = dyn_cast(VD); TransAssert(FD && "Bad FD!\n"); unsigned int Idx = FD->getFieldIndex(); Idxs.push_back(Idx); E = ME->getBase(); } else if (SC == Expr::ArraySubscriptExprClass) { const ArraySubscriptExpr *ASE = dyn_cast(E); const Expr *IdxE = ASE->getIdx(); unsigned int Idx = 0; Expr::EvalResult Result; // If we cannot have an integeral index, use 0. if (IdxE && IdxE->EvaluateAsInt(Result, *Context)) { llvm::APSInt IVal = Result.Val.getInt(); std::string IntStr = IVal.toString(10); std::stringstream TmpSS(IntStr); if (!(TmpSS >> Idx)) TransAssert(0 && "Non-integer value!"); } Idxs.push_back(Idx); E = ASE->getBase(); } else { break; } } return BaseE; } const Expr *Transformation::getBaseExprAndIdxExprs( const ArraySubscriptExpr *ASE, ExprVector &IdxExprs) { const Expr *BaseE = NULL; while (ASE) { const Expr *IdxE = ASE->getIdx(); IdxExprs.push_back(IdxE); BaseE = ASE->getBase()->IgnoreParenCasts(); ASE = dyn_cast(BaseE); } return BaseE; } const Type *Transformation::getBasePointerElemType(const Type *Ty) { QualType QT = Ty->getPointeeType(); while (!QT.isNull()) { Ty = QT.getTypePtr(); QT = Ty->getPointeeType(); } TransAssert(Ty && "NULL Type Ptr!"); return Ty; } int Transformation::getIndexAsInteger(const Expr *E) { Expr::EvalResult Result; if (!E->EvaluateAsInt(Result, *Context)) TransAssert(0 && "Failed to Evaluate index!"); int Idx; llvm::APSInt IVal = Result.Val.getInt(); Idx = (int)(*IVal.getRawData()); return Idx; } const Type* Transformation::getBaseType(const Type *T) { if (T->isPointerType() || T->isReferenceType()) return getBaseType(T->getPointeeType().getTypePtr()); else if (T->isRecordType()) T = T->getAs(); else if (T->isEnumeralType()) T = T->getAs(); else if (T->getTypeClass() == Type::Typedef) T = T->getAs(); else if (T->isArrayType()) return getBaseType(T->castAsArrayTypeUnsafe()-> getElementType().getTypePtr()); return T; } // Lookup a function decl from a top-level DeclContext // It's slow... const FunctionDecl *Transformation::lookupFunctionDeclInGlobal( DeclarationName &DName, const DeclContext *Ctx) { DeclContext::lookup_result Result = Ctx->lookup(DName); for (auto I = Result.begin(), E = Result.end(); I != E; ++I) { if (const FunctionDecl *FD = dyn_cast(*I)) { return FD; } const FunctionTemplateDecl *TD = NULL; if (const UsingShadowDecl *USD = dyn_cast(*I)) { TD = dyn_cast(USD->getTargetDecl()); } else { TD = dyn_cast(*I); } if (TD) return TD->getTemplatedDecl(); } for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if (const ClassTemplateDecl *ClassTemplate = dyn_cast(*I)) { const CXXRecordDecl *CXXRD = ClassTemplate->getTemplatedDecl(); if (const FunctionDecl *FD = lookupFunctionDeclInGlobal(DName, CXXRD)) { return FD; } } const DeclContext *SubCtx = dyn_cast(*I); if (!SubCtx || dyn_cast(SubCtx)) continue; if (const FunctionDecl *FD = lookupFunctionDeclInGlobal(DName, SubCtx)) { return FD; } } return NULL; } const FunctionDecl *Transformation::lookupFunctionDeclFromBases( DeclarationName &DName, const CXXRecordDecl *CXXRD, DeclContextSet &VisitedCtxs) { if (!CXXRD->hasDefinition()) { return NULL; } for (CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(), E = CXXRD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); // it's not always the case we could resolve a base specifier, e.g. // Ty is of DependentName if (!Base) continue; const CXXRecordDecl *BaseDef = Base->getDefinition(); if (!BaseDef) continue; if (const FunctionDecl *FD = lookupFunctionDecl(DName, BaseDef, VisitedCtxs)) return FD; } return NULL; } const FunctionDecl *Transformation::lookupFunctionDeclFromCtx( DeclarationName &DName, const DeclContext *Ctx, DeclContextSet &VisitedCtxs) { if (dyn_cast(Ctx)) return NULL; DeclContext::lookup_result Result = Ctx->lookup(DName); for (auto I = Result.begin(), E = Result.end(); I != E; ++I) { if (const FunctionDecl *FD = dyn_cast(*I)) { return FD; } const FunctionTemplateDecl *TD = NULL; if (const UsingShadowDecl *USD = dyn_cast(*I)) { TD = dyn_cast(USD->getTargetDecl()); } else { TD = dyn_cast(*I); } if (TD) return TD->getTemplatedDecl(); if (const UnresolvedUsingValueDecl *UUD = dyn_cast(*I)) { const NestedNameSpecifier *NNS = UUD->getQualifier(); const DeclContext *DeclCtx = getDeclContextFromSpecifier(NNS); if (!DeclCtx) continue; if (const FunctionDecl *FD = lookupFunctionDecl(DName, DeclCtx, VisitedCtxs)) return FD; } } return NULL; } const FunctionDecl *Transformation::lookupFunctionDecl( DeclarationName &DName, const DeclContext *Ctx, DeclContextSet &VisitedCtxs) { if (dyn_cast(Ctx)) return NULL; if (VisitedCtxs.count(Ctx)) return NULL; VisitedCtxs.insert(Ctx); if (const FunctionDecl *FD = lookupFunctionDeclFromCtx(DName, Ctx, VisitedCtxs)) return FD; // lookup base classes: // this would be slow and may re-visit some Ctx. // Probably we should cache those Ctx(s) which have been visited // to speedup lookup if (Ctx->isRecord()) { const RecordDecl *RD = dyn_cast(Ctx); if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { if (const FunctionDecl *FD = lookupFunctionDeclFromBases(DName, CXXRD, VisitedCtxs)) return FD; } } for (auto *I : Ctx->using_directives()) { const NamespaceDecl *ND = I->getNominatedNamespace(); // avoid infinite recursion if (ND->getLookupParent() == Ctx) return NULL; if (const FunctionDecl *FD = lookupFunctionDecl(DName, ND, VisitedCtxs)) return FD; } const DeclContext *ParentCtx = Ctx->getLookupParent(); if (!ParentCtx || dyn_cast(ParentCtx)) return NULL; return lookupFunctionDecl(DName, ParentCtx, VisitedCtxs); } const DeclContext *Transformation::getDeclContextFromSpecifier( const NestedNameSpecifier *NNS) { for (; NNS; NNS = NNS->getPrefix()) { NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); switch (Kind) { case NestedNameSpecifier::Namespace: { return NNS->getAsNamespace()->getCanonicalDecl(); } case NestedNameSpecifier::NamespaceAlias: { const NamespaceAliasDecl *NAD = NNS->getAsNamespaceAlias(); return NAD->getNamespace()->getCanonicalDecl(); } case NestedNameSpecifier::TypeSpec: // Fall-through case NestedNameSpecifier::TypeSpecWithTemplate: { const Type *Ty = NNS->getAsType(); if (const RecordType *RT = Ty->getAs()) return RT->getDecl(); if (const TypedefType *TT = Ty->getAs()) { const TypedefNameDecl *TypeDecl = TT->getDecl(); const Type *UnderlyingTy = TypeDecl->getUnderlyingType().getTypePtr(); if (const RecordType *RT = UnderlyingTy->getAs()) return RT->getDecl(); if (const TemplateSpecializationType *TST = UnderlyingTy->getAs()) { return getBaseDeclFromTemplateSpecializationType(TST); } } break; } default: break; } } return NULL; } bool Transformation::isSpecialRecordDecl(const RecordDecl *RD) { std::string Name = RD->getNameAsString(); return (Name == "__va_list_tag"); } const CXXRecordDecl *Transformation::getBaseDeclFromTemplateSpecializationType( const TemplateSpecializationType *TSTy) { TemplateName TplName = TSTy->getTemplateName(); TemplateDecl *TplD = TplName.getAsTemplateDecl(); TransAssert(TplD && "Invalid TemplateDecl!"); if (dyn_cast(TplD)) { return NULL; } NamedDecl *ND = TplD->getTemplatedDecl(); TransAssert(ND && "Invalid NamedDecl!"); if (TypedefNameDecl *TdefD = dyn_cast(ND)) { const Type *UnderlyingTy = TdefD->getUnderlyingType().getTypePtr(); return getBaseDeclFromType(UnderlyingTy); } const CXXRecordDecl *CXXRD = dyn_cast(ND); TransAssert(CXXRD && "Invalid CXXRD!"); if (CXXRD->hasDefinition()) return CXXRD->getDefinition(); else return CXXRD; } // This function could return NULL const CXXRecordDecl *Transformation::getBaseDeclFromType(const Type *Ty) { const CXXRecordDecl *Base = NULL; Type::TypeClass TyClass = Ty->getTypeClass(); switch (TyClass) { case Type::TemplateSpecialization: { const TemplateSpecializationType *TSTy = dyn_cast(Ty); return getBaseDeclFromTemplateSpecializationType(TSTy); } case Type::DependentTemplateSpecialization: { return NULL; } case Type::Elaborated: { const ElaboratedType *ETy = dyn_cast(Ty); const Type *NamedT = ETy->getNamedType().getTypePtr(); return getBaseDeclFromType(NamedT); } case Type::Paren: { const ParenType *PT = dyn_cast(Ty); const Type *InnerTy = PT->getInnerType().getTypePtr(); return getBaseDeclFromType(InnerTy); } case Type::Typedef: { const TypedefType *TdefTy = dyn_cast(Ty); const TypedefNameDecl *TdefD = TdefTy->getDecl(); const Type *UnderlyingTy = TdefD->getUnderlyingType().getTypePtr(); return getBaseDeclFromType(UnderlyingTy); } case Type::Decltype: { const DecltypeType *DT = dyn_cast(Ty); const Type *UnderlyingTy = DT->getUnderlyingType().getTypePtr(); return getBaseDeclFromType(UnderlyingTy); } case Type::ConstantArray: case Type::DependentSizedArray: case Type::IncompleteArray: case Type::VariableArray: { // fall-through const ArrayType *AT = dyn_cast(Ty); const Type *ElemTy = AT->getElementType().getTypePtr(); return getBaseDeclFromType(ElemTy); } case Type::MemberPointer: { const MemberPointerType *MPT = dyn_cast(Ty); const Type *PT = MPT->getPointeeType().getTypePtr(); return getBaseDeclFromType(PT); } case Type::Pointer: { const PointerType *PT = dyn_cast(Ty); const Type *PTy = PT->getPointeeType().getTypePtr(); return getBaseDeclFromType(PTy); } case Type::SubstTemplateTypeParm: { const SubstTemplateTypeParmType *TP = dyn_cast(Ty); const Type *ST = TP->getReplacementType().getTypePtr(); return getBaseDeclFromType(ST); } case Type::DependentName: { // It's not always the case that we could resolve a dependent name type. // For example, // template // struct AAA { typedef T2 new_type; }; // template // struct BBB : public AAA::new_type { }; // In the above code, we can't figure out what new_type refers to // until BBB is instantiated // Due to this reason, simply return NULL from here. return NULL; } case Type::TemplateTypeParm: { // Yet another case we might not know the base class, e.g., // template // class AAA { // struct BBB : T1 {}; // }; return NULL; } case Type::Enum: case Type::FunctionProto: case Type::FunctionNoProto: case Type::SubstTemplateTypeParmPack: case Type::PackExpansion: case Type::Vector: case Type::ExtVector: case Type::Builtin: // fall-through return NULL; case Type::Auto: { const AutoType *AutoTy = dyn_cast(Ty); const Type *AT = AutoTy->getDeducedType().getTypePtrOrNull(); if (!AT) return NULL; return getBaseDeclFromType(AT); } case Type::TypeOfExpr: { const Expr *E = dyn_cast(Ty)->getUnderlyingExpr(); return getBaseDeclFromType(E->getType().getTypePtr()); } case Type::TypeOf: { return getBaseDeclFromType( dyn_cast(Ty)->getUnderlyingType().getTypePtr()); } default: Base = Ty->getAsCXXRecordDecl(); TransAssert(Base && "Bad base class type!"); // getAsCXXRecordDecl could return a ClassTemplateSpecializationDecl. // For example: // template class AAA { }; // typedef AAA BBB; // class CCC : BBB { }; // In the above code, BBB is of type ClassTemplateSpecializationDecl if (const ClassTemplateSpecializationDecl *CTSDecl = dyn_cast(Base)) { Base = CTSDecl->getSpecializedTemplate()->getTemplatedDecl(); TransAssert(Base && "Bad base decl from ClassTemplateSpecializationDecl!"); } } return Base; } bool Transformation::isParameterPack(const NamedDecl *ND) { if (const NonTypeTemplateParmDecl *NonTypeD = dyn_cast(ND)) { return NonTypeD->isParameterPack(); } else if (const TemplateTypeParmDecl *TypeD = dyn_cast(ND)) { return TypeD->isParameterPack(); } else if (const TemplateTemplateParmDecl *TmplD = dyn_cast(ND)) { return TmplD->isParameterPack(); } else { TransAssert(0 && "Unknown template parameter type!"); return false; } } unsigned Transformation::getNumCtorWrittenInitializers( const CXXConstructorDecl &Ctor) { unsigned Num = 0; for (CXXConstructorDecl::init_const_iterator I = Ctor.init_begin(), E = Ctor.init_end(); I != E; ++I) { if ((*I)->isWritten()) Num++; } return Num; } bool Transformation::isBeforeColonColon(TypeLoc &Loc) { SourceLocation EndLoc = Loc.getEndLoc(); SourceLocation ColonColonLoc = Lexer::findLocationAfterToken(EndLoc, tok::coloncolon, *SrcManager, Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); return ColonColonLoc.isValid(); } bool Transformation::replaceDependentNameString(const Type *Ty, const TemplateArgument *Args, unsigned NumArgs, std::string &Str, bool &Typename) { TransAssert((Ty->getTypeClass() == Type::DependentName) && "Not DependentNameType!"); const DependentNameType *DNT = dyn_cast(Ty); const IdentifierInfo *IdInfo = DNT->getIdentifier(); if (!IdInfo) return false; const NestedNameSpecifier *Specifier = DNT->getQualifier(); if (!Specifier) return false; const Type *DependentTy = Specifier->getAsType(); if (!DependentTy) return false; const TemplateTypeParmType *ParmTy = DependentTy->getAs(); if (!ParmTy) return false; unsigned Idx = ParmTy->getIndex(); TransAssert((Idx < NumArgs) && "Bad Parm Index!"); const TemplateArgument Arg = Args[Idx]; if (Arg.getKind() != TemplateArgument::Type) return false; QualType ArgQT = Arg.getAsType(); ArgQT.getAsStringInternal(Str, Context->getPrintingPolicy()); Str += "::"; Str += IdInfo->getName(); Typename = true; return true; } bool Transformation::getTemplateTypeParmString( const TemplateTypeParmType *ParmTy, const TemplateArgument *Args, unsigned NumArgs, std::string &Str) { unsigned Idx = ParmTy->getIndex(); // we could have default template args, skip this case for now if (Idx >= NumArgs) return false; const TemplateArgument Arg = Args[Idx]; if (Arg.getKind() != TemplateArgument::Type) return false; QualType ArgQT = Arg.getAsType(); ArgQT.getAsStringInternal(Str, Context->getPrintingPolicy()); return true; } bool Transformation::getTypedefString(const StringRef &Name, const CXXRecordDecl *CXXRD, const TemplateArgument *Args, unsigned NumArgs, std::string &Str, bool &Typename) { Str = ""; for (DeclContext::decl_iterator I = CXXRD->decls_begin(), E = CXXRD->decls_end(); I != E; ++I) { const TypedefDecl *D = dyn_cast(*I); if (!D || (D->getNameAsString() != Name)) continue; const Type *UnderlyingTy = D->getUnderlyingType().getTypePtr(); Type::TypeClass TC = UnderlyingTy->getTypeClass(); if (TC == Type::DependentName) { if (replaceDependentNameString(UnderlyingTy, Args, NumArgs, Str, Typename)) return true; } else if (const TemplateTypeParmType *ParmTy = UnderlyingTy->getAs()) { if (getTemplateTypeParmString(ParmTy, Args, NumArgs, Str)) return true; } } // check base class for (CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(), E = CXXRD->bases_end(); I != E; ++I) { const CXXBaseSpecifier *BS = I; const Type *Ty = BS->getType().getTypePtr(); const CXXRecordDecl *Base = getBaseDeclFromType(Ty); // it could happen if we have a dependent base specifier if (!Base) continue; const CXXRecordDecl *BaseDef = Base->getDefinition(); if (!BaseDef) continue; if (getTypedefString(Name, BaseDef, Args, NumArgs, Str, Typename)) return true; } // TODO: really simplified lookup process, maybe need // to check other decl context? return false; } bool Transformation::getDependentNameTypeString( const DependentNameType *DNT, std::string &Str, bool &Typename) { const IdentifierInfo *IdInfo = DNT->getIdentifier(); if (!IdInfo) return false; const NestedNameSpecifier *Specifier = DNT->getQualifier(); if (!Specifier) return false; const Type *Ty = Specifier->getAsType(); if (!Ty) return false; const CXXRecordDecl *Base = getBaseDeclFromType(Ty); if (!Base) return false; const CXXRecordDecl *BaseDef = Base->getDefinition(); if (!BaseDef) return false; unsigned NumArgs = 0; const TemplateArgument *Args = NULL; if (const TemplateSpecializationType *TST = Ty->getAs()) { NumArgs = TST->getNumArgs(); Args = TST->getArgs(); } return getTypedefString(IdInfo->getName(), BaseDef, Args, NumArgs, Str, Typename); } bool Transformation::getTypeString(const QualType &QT, std::string &Str, bool &Typename) { const Type *Ty = QT.getTypePtr(); Type::TypeClass TC = Ty->getTypeClass(); switch (TC) { case Type::SubstTemplateTypeParm: { const SubstTemplateTypeParmType *TP = dyn_cast(Ty); return getTypeString(TP->getReplacementType(), Str, Typename); } case Type::Elaborated: { const ElaboratedType *ETy = dyn_cast(Ty); return getTypeString(ETy->getNamedType(), Str, Typename); } case Type::Typedef: { const TypedefType *TdefTy = dyn_cast(Ty); const TypedefNameDecl *TdefD = TdefTy->getDecl(); return getTypeString(TdefD->getUnderlyingType(), Str, Typename); } case Type::DependentName: { const DependentNameType *DNT = dyn_cast(Ty); return getDependentNameTypeString(DNT, Str, Typename); } case Type::Record: case Type::Builtin: { // fall-through QT.getAsStringInternal(Str, Context->getPrintingPolicy()); return true; } default: return false; } TransAssert(0 && "Unreachable code!"); return false; } unsigned Transformation::getNumExplicitDecls(const CXXRecordDecl *CXXRD) { const DeclContext *Ctx = dyn_cast(CXXRD); TransAssert(Ctx && "Invalid DeclContext!"); unsigned Num = 0; for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if (!(*I)->isImplicit()) Num++; } return Num; } bool Transformation::isInIncludedFile(SourceLocation Loc) const { Loc = getRealLocation(Loc); return SrcManager->getFileID(Loc) != SrcManager->getMainFileID(); } bool Transformation::isInIncludedFile(const Decl *D) const { return isInIncludedFile(D->getLocation()); } bool Transformation::isInIncludedFile(const Stmt *S) const { return isInIncludedFile(S->getBeginLoc()); } SourceLocation Transformation::getRealLocation(SourceLocation Loc) const { if (Loc.isMacroID()) return SrcManager->getExpansionLoc(Loc); return Loc; } bool Transformation::isDeclaringRecordDecl(const RecordDecl *RD) { SourceLocation SemiLoc = Lexer::findLocationAfterToken(RD->getSourceRange().getEnd(), tok::semi, *SrcManager, Context->getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); return SemiLoc.isInvalid(); } Transformation::~Transformation(void) { RewriteUtils::Finalize(); } cvise-2.3.0/clang_delta/Transformation.h000066400000000000000000000241651402162750500202530ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef TRANSFORMATION_H #define TRANSFORMATION_H #include #include #include #include "llvm/ADT/SmallPtrSet.h" #include "clang/AST/ASTConsumer.h" #include "clang/Rewrite/Core/Rewriter.h" #include "RewriteUtils.h" namespace clang { class CompilerInstance; class ASTContext; class SourceManager; class Decl; class Expr; class ArrayType; class InitListExpr; class ArraySubscriptExpr; class MemberExpr; class Type; class ConstantArrayType; class DeclContext; class DeclarationName; class NestedNameSpecifier; class TemplateSpecializationType; class NamedDecl; class CXXConstructorDecl; class TypeLoc; class TemplateArgument; class TemplateTypeParmType; class DependentNameType; class QualType; } typedef enum { TransSuccess = 0, TransInternalError, TransMaxInstanceError, TransMaxVarsError, TransMaxClassesError, TransNoValidVarsError, TransNoValidFunsError, TransNoValidParamsError, TransNoTextModificationError, TransToCounterTooBigError } TransformationError; namespace clang_delta_common_visitor { template class CommonRenameClassRewriteVisitor; } class Transformation : public clang::ASTConsumer { template friend class clang_delta_common_visitor::CommonRenameClassRewriteVisitor; public: Transformation(const char *TransName, const char *Desc) : Name(TransName), TransformationCounter(-1), ValidInstanceNum(0), QueryInstanceOnly(false), Context(NULL), SrcManager(NULL), TransError(TransSuccess), DescriptionString(Desc), RewriteHelper(NULL), Rewritten(false), MultipleRewrites(false), ToCounter(-1), DoReplacement(false), DoPreserveRoutine(false), CheckReference(false), WarnOnCounterOutOfBounds(false) { // Nothing to do } Transformation(const char *TransName, const char *Desc, bool MultipleRewritesFlag) : Name(TransName), TransformationCounter(-1), ValidInstanceNum(0), QueryInstanceOnly(false), Context(NULL), SrcManager(NULL), TransError(TransSuccess), DescriptionString(Desc), RewriteHelper(NULL), Rewritten(false), MultipleRewrites(MultipleRewritesFlag), ToCounter(-1), DoReplacement(false), DoPreserveRoutine(false), CheckReference(false), WarnOnCounterOutOfBounds(false) { // Nothing to do } virtual ~Transformation(); void outputOriginalSource(llvm::raw_ostream &OutStream); void outputTransformedSource(llvm::raw_ostream &OutStream); void setTransformationCounter(int Counter) { TransformationCounter = Counter; } void setToCounter(int Counter) { ToCounter = Counter; } void setWarnOnCounterOutOfBounds(bool Flag) { WarnOnCounterOutOfBounds = Flag; } bool isMultipleRewritesEnabled() { return MultipleRewrites; } void setQueryInstanceFlag(bool Flag) { QueryInstanceOnly = Flag; } void setReplacement(const std::string &Str) { Replacement = Str; DoReplacement = true; } void setPreserveRoutine(const std::string &Str) { PreserveRoutine = Str; DoPreserveRoutine = true; } void setReferenceValue(const std::string &Str) { ReferenceValue = Str; CheckReference = true; } bool transSuccess() { return (TransError == TransSuccess); } bool transMaxInstanceError() { return (TransError == TransMaxInstanceError); } bool transInternalError() { return (TransError == TransInternalError); } bool isInvalidCounterError() { return ((TransError == TransMaxInstanceError) || (TransError == TransToCounterTooBigError)); } std::string &getDescription() { return DescriptionString; } void getTransErrorMsg(std::string &ErrorMsg); bool checkCounterValidity(); int getNumTransformationInstances() { return ValidInstanceNum; } virtual bool skipCounter() { return false; } protected: typedef llvm::SmallVector IndexVector; typedef llvm::SmallVector ArraySubTypeVector; typedef llvm::SmallVector ExprVector; typedef llvm::SmallPtrSet DeclContextSet; unsigned int getArrayDimension(const clang::ArrayType *ArrayTy); unsigned int getArrayDimensionAndTypes(const clang::ArrayType *ArrayTy, ArraySubTypeVector &TyVec); virtual void Initialize(clang::ASTContext &context); const clang::Type * getArrayBaseElemType(const clang::ArrayType *ArrayTy); const clang::Expr * getArraySubscriptElem(const clang::ArraySubscriptExpr *ASE); const clang::Expr * ignoreSubscriptExprParenCasts(const clang::Expr *E); const clang::Expr *getMemberExprElem(const clang::MemberExpr *ME); const clang::Expr * getArrayBaseExprAndIdxs(const clang::ArraySubscriptExpr *ASE, IndexVector &Idxs); const clang::Expr *getBaseExprAndIdxExprs( const clang::ArraySubscriptExpr *ASE, ExprVector &IdxExprs); const clang::Expr *getInitExprByIndex(IndexVector &Idxs, const clang::InitListExpr *ILE); unsigned int getConstArraySize(const clang::ConstantArrayType *CstArrayTy); const clang::Expr *getMemberExprBaseExprAndIdxs(const clang::MemberExpr *ME, IndexVector &Idx); const clang::Expr *getInitExprFromBase(const clang::Expr *BaseE, IndexVector &Idxs); const clang::Expr *getBaseExprAndIdxs(const clang::Expr *E, IndexVector &Idxs); const clang::Type *getBasePointerElemType(const clang::Type *Ty); const clang::Type* getBaseType(const clang::Type *T); int getIndexAsInteger(const clang::Expr *E); bool isCXXMemberExpr(const clang::MemberExpr *ME); const clang::FunctionDecl *lookupFunctionDecl( clang::DeclarationName &DName, const clang::DeclContext *Ctx, DeclContextSet &VisitedCtxs); const clang::FunctionDecl *lookupFunctionDeclFromCtx( clang::DeclarationName &DName, const clang::DeclContext *Ctx, DeclContextSet &VisitedCtxs); const clang::FunctionDecl *lookupFunctionDeclFromBases( clang::DeclarationName &DName, const clang::CXXRecordDecl *CXXRD, DeclContextSet &VisitedCtxs); const clang::FunctionDecl *lookupFunctionDeclInGlobal( clang::DeclarationName &DName, const clang::DeclContext *Ctx); const clang::DeclContext *getDeclContextFromSpecifier( const clang::NestedNameSpecifier *NNS); bool isSpecialRecordDecl(const clang::RecordDecl *RD); const clang::CXXRecordDecl *getBaseDeclFromType(const clang::Type *Ty); const clang::CXXRecordDecl *getBaseDeclFromTemplateSpecializationType( const clang::TemplateSpecializationType *TSTy); bool isParameterPack(const clang::NamedDecl *ND); unsigned getNumCtorWrittenInitializers(const clang::CXXConstructorDecl &Ctor); bool isBeforeColonColon(clang::TypeLoc &Loc); bool getTypeString(const clang::QualType &QT, std::string &Str, bool &Typename); bool getTypedefString(const llvm::StringRef &Name, const clang::CXXRecordDecl *CXXRD, const clang::TemplateArgument *Args, unsigned NumArgs, std::string &Str, bool &Typename); bool getDependentNameTypeString(const clang::DependentNameType *DNT, std::string &Str, bool &Typename); bool replaceDependentNameString(const clang::Type *Ty, const clang::TemplateArgument *Args, unsigned NumArgs, std::string &Str, bool &Typename); bool getTemplateTypeParmString(const clang::TemplateTypeParmType *ParmTy, const clang::TemplateArgument *Args, unsigned NumArgs, std::string &Str); unsigned getNumExplicitDecls(const clang::CXXRecordDecl *CXXRD); bool isInIncludedFile(clang::SourceLocation Loc) const; bool isInIncludedFile(const clang::Decl *D) const; bool isInIncludedFile(const clang::Stmt *S) const; bool isDeclaringRecordDecl(const clang::RecordDecl *RD); // If the location is a MacroID, get its expansion location. // Otherwise, just return the location. clang::SourceLocation getRealLocation(clang::SourceLocation Loc) const; const std::string Name; int TransformationCounter; int ValidInstanceNum; bool QueryInstanceOnly; clang::ASTContext *Context; clang::SourceManager *SrcManager; clang::Rewriter TheRewriter; TransformationError TransError; std::string DescriptionString; RewriteUtils *RewriteHelper; bool Rewritten; const bool MultipleRewrites; int ToCounter; bool DoReplacement; std::string Replacement; bool DoPreserveRoutine; std::string PreserveRoutine; bool CheckReference; std::string ReferenceValue; bool WarnOnCounterOutOfBounds; }; class TransNameQueryVisitor; class TransNameQueryWrap { friend class TransNameQueryVisitor; public: explicit TransNameQueryWrap(const std::string &Prefix); ~TransNameQueryWrap(); unsigned int getMaxNamePostfix() { return MaxPostfix; } bool TraverseDecl(clang::Decl *D); private: std::string NamePrefix; unsigned int MaxPostfix; TransNameQueryVisitor *NameQueryVisitor; // Unimplemented TransNameQueryWrap(); TransNameQueryWrap(const TransNameQueryWrap &); void operator=(const TransNameQueryWrap &); }; #endif cvise-2.3.0/clang_delta/TransformationManager.cpp000066400000000000000000000344671402162750500221070ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "TransformationManager.h" #include #include #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Parse/ParseAST.h" #include "Transformation.h" using namespace std; using namespace clang; int TransformationManager::ErrorInvalidCounter = 1; TransformationManager* TransformationManager::Instance; std::map * TransformationManager::TransformationsMapPtr; TransformationManager *TransformationManager::GetInstance() { if (TransformationManager::Instance) return TransformationManager::Instance; TransformationManager::Instance = new TransformationManager(); assert(TransformationManager::Instance); TransformationManager::Instance->TransformationsMap = *TransformationManager::TransformationsMapPtr; return TransformationManager::Instance; } Preprocessor &TransformationManager::getPreprocessor() { return GetInstance()->ClangInstance->getPreprocessor(); } bool TransformationManager::isCXXLangOpt() { TransAssert(TransformationManager::Instance && "Invalid Instance!"); TransAssert(TransformationManager::Instance->ClangInstance && "Invalid ClangInstance!"); return (TransformationManager::Instance->ClangInstance->getLangOpts() .CPlusPlus); } bool TransformationManager::isCLangOpt() { TransAssert(TransformationManager::Instance && "Invalid Instance!"); TransAssert(TransformationManager::Instance->ClangInstance && "Invalid ClangInstance!"); return (TransformationManager::Instance->ClangInstance->getLangOpts() .C99); } bool TransformationManager::isOpenCLLangOpt() { TransAssert(TransformationManager::Instance && "Invalid Instance!"); TransAssert(TransformationManager::Instance->ClangInstance && "Invalid ClangInstance!"); return (TransformationManager::Instance->ClangInstance->getLangOpts() .OpenCL); } bool TransformationManager::initializeCompilerInstance(std::string &ErrorMsg) { if (ClangInstance) { ErrorMsg = "CompilerInstance has been initialized!"; return false; } ClangInstance = new CompilerInstance(); assert(ClangInstance); ClangInstance->createDiagnostics(); TargetOptions &TargetOpts = ClangInstance->getTargetOpts(); #if LLVM_VERSION_MAJOR < 12 PreprocessorOptions &PPOpts = ClangInstance->getPreprocessorOpts(); #endif if (const char *env = getenv("CVISE_TARGET_TRIPLE")) { TargetOpts.Triple = std::string(env); } else { TargetOpts.Triple = LLVM_DEFAULT_TARGET_TRIPLE; } llvm::Triple T(TargetOpts.Triple); CompilerInvocation &Invocation = ClangInstance->getInvocation(); InputKind IK = FrontendOptions::getInputKindForExtension( StringRef(SrcFileName).rsplit('.').second); LangStandard::Kind LSTD = LangStandard::lang_unspecified; if (SetCXXStandard) { if (!CXXStandard.compare("c++98")) LSTD = LangStandard::Kind::lang_cxx98; else if (!CXXStandard.compare("c++11")) LSTD = LangStandard::Kind::lang_cxx11; else if (!CXXStandard.compare("c++14")) LSTD = LangStandard::Kind::lang_cxx14; else if (!CXXStandard.compare("c++17")) LSTD = LangStandard::Kind::lang_cxx17; else if (!CXXStandard.compare("c++20")) #if LLVM_VERSION_MAJOR < 10 LSTD = LangStandard::Kind::lang_cxx2a; #else LSTD = LangStandard::Kind::lang_cxx20; #endif else { ErrorMsg = "Can't parse CXXStandard option argument!"; return false; } } #if LLVM_VERSION_MAJOR < 10 if (IK.getLanguage() == InputKind::C) { Invocation.setLangDefaults(ClangInstance->getLangOpts(), InputKind::C, T, PPOpts); } else if (IK.getLanguage() == InputKind::CXX) { // ISSUE: it might cause some problems when building AST // for a function which has a non-declared callee, e.g., // It results an empty AST for the caller. Invocation.setLangDefaults(ClangInstance->getLangOpts(), InputKind::CXX, T, PPOpts, LSTD); } else if(IK.getLanguage() == InputKind::OpenCL) { #elif LLVM_VERSION_MAJOR < 12 if (IK.getLanguage() == Language::C) { Invocation.setLangDefaults(ClangInstance->getLangOpts(), InputKind(Language::C), T, PPOpts); } else if (IK.getLanguage() == Language::CXX) { // ISSUE: it might cause some problems when building AST // for a function which has a non-declared callee, e.g., // It results an empty AST for the caller. Invocation.setLangDefaults(ClangInstance->getLangOpts(), InputKind(Language::CXX), T, PPOpts, LSTD); } else if(IK.getLanguage() == Language::OpenCL) { #else vector includes; if (IK.getLanguage() == Language::C) { Invocation.setLangDefaults(ClangInstance->getLangOpts(), InputKind(Language::C), T, includes); } else if (IK.getLanguage() == Language::CXX) { // ISSUE: it might cause some problems when building AST // for a function which has a non-declared callee, e.g., // It results an empty AST for the caller. Invocation.setLangDefaults(ClangInstance->getLangOpts(), InputKind(Language::CXX), T, includes, LSTD); } else if(IK.getLanguage() == Language::OpenCL) { #endif //Commandline parameters std::vector Args; Args.push_back("-x"); Args.push_back("cl"); Args.push_back("-Dcl_clang_storage_class_specifiers"); const char *CLCPath = getenv("CVISE_LIBCLC_INCLUDE_PATH"); ClangInstance->createFileManager(); if(CLCPath != NULL && ClangInstance->hasFileManager() && ClangInstance->getFileManager().getDirectory(CLCPath, false)) { Args.push_back("-I"); Args.push_back(CLCPath); } Args.push_back("-include"); Args.push_back("clc/clc.h"); Args.push_back("-fno-builtin"); CompilerInvocation::CreateFromArgs(Invocation, #if LLVM_VERSION_MAJOR >= 10 Args, #else &Args[0], &Args[0] + Args.size(), #endif ClangInstance->getDiagnostics()); Invocation.setLangDefaults(ClangInstance->getLangOpts(), #if LLVM_VERSION_MAJOR >= 10 InputKind(Language::OpenCL), #else InputKind::OpenCL, #endif #if LLVM_VERSION_MAJOR < 12 T, PPOpts); #else T, includes); #endif } else { ErrorMsg = "Unsupported file type!"; return false; } TargetInfo *Target = TargetInfo::CreateTargetInfo(ClangInstance->getDiagnostics(), ClangInstance->getInvocation().TargetOpts); ClangInstance->setTarget(Target); if (const char *env = getenv("CVISE_INCLUDE_PATH")) { HeaderSearchOptions &HeaderSearchOpts = ClangInstance->getHeaderSearchOpts(); const std::size_t npos = std::string::npos; std::string text = env; std::size_t now = 0, next = 0; do { next = text.find(':', now); std::size_t len = (next == npos) ? npos : (next - now); HeaderSearchOpts.AddPath(text.substr(now, len), clang::frontend::Angled, false, false); now = next + 1; } while(next != npos); } ClangInstance->createFileManager(); ClangInstance->createSourceManager(ClangInstance->getFileManager()); ClangInstance->createPreprocessor(TU_Complete); DiagnosticConsumer &DgClient = ClangInstance->getDiagnosticClient(); DgClient.BeginSourceFile(ClangInstance->getLangOpts(), &ClangInstance->getPreprocessor()); ClangInstance->createASTContext(); // It's not elegant to initialize these two here... Ideally, we // would put them in doTransformation, but we need these two // flags being set before Transformation::Initialize, which // is invoked through ClangInstance->setASTConsumer. if (DoReplacement) CurrentTransformationImpl->setReplacement(Replacement); if (DoPreserveRoutine) CurrentTransformationImpl->setPreserveRoutine(PreserveRoutine); if (CheckReference) CurrentTransformationImpl->setReferenceValue(ReferenceValue); assert(CurrentTransformationImpl && "Bad transformation instance!"); ClangInstance->setASTConsumer( std::unique_ptr(CurrentTransformationImpl)); Preprocessor &PP = ClangInstance->getPreprocessor(); PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), PP.getLangOpts()); if (!ClangInstance->InitializeSourceManager(FrontendInputFile(SrcFileName, IK))) { ErrorMsg = "Cannot open source file!"; return false; } return true; } void TransformationManager::Finalize() { assert(TransformationManager::Instance); std::map::iterator I, E; for (I = Instance->TransformationsMap.begin(), E = Instance->TransformationsMap.end(); I != E; ++I) { // CurrentTransformationImpl will be freed by ClangInstance if ((*I).second != Instance->CurrentTransformationImpl) delete (*I).second; } delete Instance->TransformationsMapPtr; delete Instance->ClangInstance; delete Instance; Instance = NULL; } llvm::raw_ostream *TransformationManager::getOutStream() { if (OutputFileName.empty()) return &(llvm::outs()); std::error_code EC; llvm::raw_fd_ostream *Out = new llvm::raw_fd_ostream( OutputFileName, EC, llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write); assert(!EC && "Cannot open output file!"); return Out; } void TransformationManager::closeOutStream(llvm::raw_ostream *OutStream) { if (!OutputFileName.empty()) delete OutStream; } bool TransformationManager::doTransformation(std::string &ErrorMsg, int &ErrorCode) { ErrorMsg = ""; ClangInstance->createSema(TU_Complete, 0); DiagnosticsEngine &Diag = ClangInstance->getDiagnostics(); Diag.setSuppressAllDiagnostics(true); Diag.setIgnoreAllWarnings(true); CurrentTransformationImpl->setWarnOnCounterOutOfBounds(WarnOnCounterOutOfBounds); CurrentTransformationImpl->setQueryInstanceFlag(QueryInstanceOnly); CurrentTransformationImpl->setTransformationCounter(TransformationCounter); if (ToCounter > 0) { if (CurrentTransformationImpl->isMultipleRewritesEnabled()) { CurrentTransformationImpl->setToCounter(ToCounter); } else { ErrorMsg = "current transformation["; ErrorMsg += CurrentTransName; ErrorMsg += "] does not support multiple rewrites!"; return false; } } ParseAST(ClangInstance->getSema()); ClangInstance->getDiagnosticClient().EndSourceFile(); if (QueryInstanceOnly) { return true; } llvm::raw_ostream *OutStream = getOutStream(); bool RV; if (CurrentTransformationImpl->transSuccess()) { CurrentTransformationImpl->outputTransformedSource(*OutStream); RV = true; } else if (CurrentTransformationImpl->transInternalError()) { CurrentTransformationImpl->outputOriginalSource(*OutStream); RV = true; } else { CurrentTransformationImpl->getTransErrorMsg(ErrorMsg); if (CurrentTransformationImpl->isInvalidCounterError()) ErrorCode = ErrorInvalidCounter; RV = false; } closeOutStream(OutStream); return RV; } bool TransformationManager::verify(std::string &ErrorMsg, int &ErrorCode) { if (!CurrentTransformationImpl) { ErrorMsg = "Empty transformation instance!"; return false; } if (CurrentTransformationImpl->skipCounter()) return true; if (TransformationCounter <= 0) { ErrorMsg = "Invalid transformation counter!"; ErrorCode = ErrorInvalidCounter; return false; } if ((ToCounter > 0) && (ToCounter < TransformationCounter)) { ErrorMsg = "to-counter value cannot be smaller than counter value!"; ErrorCode = ErrorInvalidCounter; return false; } return true; } void TransformationManager::registerTransformation( const char *TransName, Transformation *TransImpl) { if (!TransformationManager::TransformationsMapPtr) { TransformationManager::TransformationsMapPtr = new std::map(); } assert((TransImpl != NULL) && "NULL Transformation!"); assert((TransformationManager::TransformationsMapPtr->find(TransName) == TransformationManager::TransformationsMapPtr->end()) && "Duplicated transformation!"); (*TransformationManager::TransformationsMapPtr)[TransName] = TransImpl; } void TransformationManager::printTransformations() { llvm::outs() << "Registered Transformations:\n"; std::map::iterator I, E; for (I = TransformationsMap.begin(), E = TransformationsMap.end(); I != E; ++I) { llvm::outs() << " [" << (*I).first << "]: "; llvm::outs() << (*I).second->getDescription() << "\n"; } } void TransformationManager::printTransformationNames() { std::map::iterator I, E; for (I = TransformationsMap.begin(), E = TransformationsMap.end(); I != E; ++I) { llvm::outs() << (*I).first << "\n"; } } void TransformationManager::outputNumTransformationInstances() { int NumInstances = CurrentTransformationImpl->getNumTransformationInstances(); llvm::outs() << "Available transformation instances: " << NumInstances << "\n"; } void TransformationManager::outputNumTransformationInstancesToStderr() { int NumInstances = CurrentTransformationImpl->getNumTransformationInstances(); cerr << "Available transformation instances: " << NumInstances << "\n"; } TransformationManager::TransformationManager() : CurrentTransformationImpl(NULL), TransformationCounter(-1), ToCounter(-1), SrcFileName(""), OutputFileName(""), CurrentTransName(""), ClangInstance(NULL), QueryInstanceOnly(false), DoReplacement(false), Replacement(""), DoPreserveRoutine(false), PreserveRoutine(""), CheckReference(false), ReferenceValue(""), SetCXXStandard(false), CXXStandard(""), WarnOnCounterOutOfBounds(false), ReportInstancesCount(false) { // Nothing to do } TransformationManager::~TransformationManager() { // Nothing to do } cvise-2.3.0/clang_delta/TransformationManager.h000066400000000000000000000106311402162750500215370ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2015, 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef TRANSFORMATION_MANAGER_H #define TRANSFORMATION_MANAGER_H #include #include #include #include "llvm/Support/raw_ostream.h" class Transformation; namespace clang { class CompilerInstance; class Preprocessor; } class TransformationManager { public: static TransformationManager *GetInstance(); static void Finalize(); static void registerTransformation(const char *TransName, Transformation *TransImpl); static bool isCXXLangOpt(); static bool isCLangOpt(); static bool isOpenCLLangOpt(); static clang::Preprocessor &getPreprocessor(); static int ErrorInvalidCounter; bool doTransformation(std::string &ErrorMsg, int &ErrorCode); bool verify(std::string &ErrorMsg, int &ErrorCode); int setTransformation(const std::string &Trans) { if (TransformationsMap.find(Trans.c_str()) == TransformationsMap.end()) return -1; CurrentTransName = Trans; CurrentTransformationImpl = TransformationsMap[Trans.c_str()]; return 0; } void setTransformationCounter(int Counter) { assert((Counter > 0) && "Bad Counter value!"); TransformationCounter = Counter; } void setToCounter(int Counter) { assert((Counter > 0) && "Bad to-counter value!"); ToCounter = Counter; } void setSrcFileName(const std::string &FileName) { assert(SrcFileName.empty() && "Could only process one file each time"); SrcFileName = FileName; } void setOutputFileName(const std::string &FileName) { OutputFileName = FileName; } void setReplacement(const std::string &Str) { Replacement = Str; DoReplacement = true; } void setPreserveRoutine(const std::string &Str) { PreserveRoutine = Str; DoPreserveRoutine = true; } void setReferenceValue(const std::string &Str) { ReferenceValue = Str; CheckReference = true; } void setQueryInstanceFlag(bool Flag) { QueryInstanceOnly = Flag; } bool getQueryInstanceFlag() { return QueryInstanceOnly; } void setCXXStandard(const std::string &Str) { CXXStandard = Str; SetCXXStandard = true; } void setReportInstancesCount(bool Flag) { ReportInstancesCount = Flag; } bool getReportInstancesCount() { return ReportInstancesCount; } void setWarnOnCounterOutOfBounds(bool Flag) { WarnOnCounterOutOfBounds = Flag; } bool initializeCompilerInstance(std::string &ErrorMsg); void outputNumTransformationInstances(); void outputNumTransformationInstancesToStderr(); void printTransformations(); void printTransformationNames(); private: TransformationManager(); ~TransformationManager(); llvm::raw_ostream *getOutStream(); void closeOutStream(llvm::raw_ostream *OutStream); static TransformationManager *Instance; static std::map *TransformationsMapPtr; std::map TransformationsMap; Transformation *CurrentTransformationImpl; int TransformationCounter; int ToCounter; std::string SrcFileName; std::string OutputFileName; std::string CurrentTransName; clang::CompilerInstance *ClangInstance; bool QueryInstanceOnly; bool DoReplacement; std::string Replacement; bool DoPreserveRoutine; std::string PreserveRoutine; bool CheckReference; std::string ReferenceValue; bool SetCXXStandard; std::string CXXStandard; bool WarnOnCounterOutOfBounds; bool ReportInstancesCount; // Unimplemented TransformationManager(const TransformationManager &); void operator=(const TransformationManager&); }; template class RegisterTransformation { public: RegisterTransformation(const char *TransName, const char *Desc) { Transformation *TransImpl = new TransformationClass(TransName, Desc); assert(TransImpl && "Fail to create TransformationClass"); TransformationManager::registerTransformation(TransName, TransImpl); } private: // Unimplemented RegisterTransformation(const RegisterTransformation &); void operator=(const RegisterTransformation &); }; #endif cvise-2.3.0/clang_delta/UnifyFunctionDecl.cpp000066400000000000000000000104201402162750500211550ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "UnifyFunctionDecl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "If a function is declared as static, make its definition \ as static as well, and remove the declaration. \n"; static RegisterTransformation Trans("unify-function-decl", DescriptionMsg); void UnifyFunctionDecl::Initialize(ASTContext &context) { Transformation::Initialize(context); } bool UnifyFunctionDecl::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { const FunctionDecl *FD = dyn_cast(*I); if (!FD) return true; if (isInIncludedFile(FD)) return true; if (!FD->hasBody()) return true; const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); if (VisitedFunctionDecls.count(CanonicalFD)) return true; VisitedFunctionDecls.insert(CanonicalFD); } return true; } void UnifyFunctionDecl::HandleTranslationUnit(ASTContext &Ctx) { doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } Ctx.getDiagnostics().setSuppressAllDiagnostics(false); TransAssert(TheFunctionDecl && "NULL TheFunctionDecl!"); TransAssert(TheFunctionDef && "NULL TheFunctionDef!"); doRewriting(); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } void UnifyFunctionDecl::doAnalysis(void) { for (FunctionDeclSet::iterator I = VisitedFunctionDecls.begin(), E = VisitedFunctionDecls.end(); I != E; ++I) { const FunctionDecl *FDDef = NULL; const FunctionDecl *FDDecl = NULL; const FunctionDecl *CanonicalFD = (*I); const FunctionDecl *FirstFD = CanonicalFD->getCanonicalDecl(); FunctionDecl::redecl_iterator RI = FirstFD->redecls_begin(); if (FirstFD->getSourceRange().isInvalid()) continue; ++RI; if (RI == FirstFD->redecls_end()) continue; const FunctionDecl *SecondFD = (*RI); if (SecondFD->getSourceRange().isInvalid()) continue; if (FirstFD->isThisDeclarationADefinition()) { FDDef = FirstFD; TransAssert(!SecondFD->isThisDeclarationADefinition() && "Duplicated Definition!"); FDDecl = SecondFD; } else if (SecondFD->isThisDeclarationADefinition()) { FDDef = SecondFD; TransAssert(!FirstFD->isThisDeclarationADefinition() && "Duplicated Definition!"); FDDecl = FirstFD; } else { continue; } if (!hasStaticKeyword(FDDecl) || hasStaticKeyword(FDDef)) continue; ValidInstanceNum++; if (TransformationCounter == ValidInstanceNum) { TheFunctionDef = FDDef; TheFunctionDecl = FDDecl; } } } bool UnifyFunctionDecl::hasStaticKeyword(const FunctionDecl *FD) { SourceRange FDRange = FD->getSourceRange(); SourceLocation StartLoc = FDRange.getBegin(); SourceLocation EndLoc = FD->getLocation(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); const char *EndBuf = SrcManager->getCharacterData(EndLoc); std::string Str; if (StartBuf == EndBuf) return false; TransAssert(StartBuf < EndBuf); size_t Off = EndBuf - StartBuf; Str.assign(StartBuf, Off); size_t Pos = Str.find("static"); return (Pos != std::string::npos); } void UnifyFunctionDecl::doRewriting(void) { SourceRange FDDefRange = TheFunctionDef->getSourceRange(); SourceLocation StartLoc = FDDefRange.getBegin(); TheRewriter.InsertTextBefore(StartLoc, "static "); std::string TmpStr; RewriteHelper->getFunctionDeclStrAndRemove(TheFunctionDecl, TmpStr); } UnifyFunctionDecl::~UnifyFunctionDecl(void) { // Nothing to do } cvise-2.3.0/clang_delta/UnifyFunctionDecl.h000066400000000000000000000027541402162750500206350ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef UNIFY_FUNCTION_DECL_H #define UNIFY_FUNCTION_DECL_H #include #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class FunctionDecl; } class UnifyFunctionDecl : public Transformation { public: UnifyFunctionDecl(const char *TransName, const char *Desc) : Transformation(TransName, Desc), TheFunctionDecl(NULL), TheFunctionDef(NULL) { } ~UnifyFunctionDecl(void); private: typedef llvm::SmallPtrSet FunctionDeclSet; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void doAnalysis(void); void doRewriting(void); bool hasStaticKeyword(const clang::FunctionDecl *FD); FunctionDeclSet VisitedFunctionDecls; const clang::FunctionDecl *TheFunctionDecl; const clang::FunctionDecl *TheFunctionDef; // Unimplemented UnifyFunctionDecl(void); UnifyFunctionDecl(const UnifyFunctionDecl &); void operator=(const UnifyFunctionDecl &); }; #endif cvise-2.3.0/clang_delta/UnionToStruct.cpp000066400000000000000000000300571402162750500203750ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "UnionToStruct.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" using namespace clang; static const char *DescriptionMsg = "Change a union declaration to a struct declaration. \ For a union declaration which has only scalar fields, i.e., fields \ with integer or pointer types, the transformation will set up an \ appropriate initializer for a variable which is declared with a union \ type under transformed: \n\ * if originally a pointer field gets initialization value, then \ other pointer fields with the same type will get the same initialization \ value, and all other fields will be initialized to 0; \n\ * if originally a integer field gets initialization value, then all \ other integer fields will be initialized to the same value, while all \ pointer fields will have 0. \n\ \n\ For other cases, all initializers will be dropped. (Note that this could \n\ bring in uninitialized local variables.) \n"; static RegisterTransformation Trans("union-to-struct", DescriptionMsg); class UnionToStructCollectionVisitor : public RecursiveASTVisitor { public: explicit UnionToStructCollectionVisitor(UnionToStruct *Instance) : ConsumerInstance(Instance) { } bool VisitFunctionDecl(FunctionDecl *FD); bool VisitVarDecl(VarDecl *VD); bool VisitFieldDecl(FieldDecl *FD); bool VisitRecordDecl(RecordDecl *RD); bool VisitDeclStmt(DeclStmt *DS); private: UnionToStruct *ConsumerInstance; }; bool UnionToStructCollectionVisitor::VisitFunctionDecl(FunctionDecl *FD) { const Type *T = FD->getReturnType().getTypePtr(); ConsumerInstance->addOneDeclarator(FD, T); return true; } bool UnionToStructCollectionVisitor::VisitVarDecl(VarDecl *VD) { const Type *T = VD->getType().getTypePtr(); ConsumerInstance->addOneDeclarator(VD, T); return true; } bool UnionToStructCollectionVisitor::VisitFieldDecl(FieldDecl *FD) { const Type *T = FD->getType().getTypePtr(); ConsumerInstance->addOneDeclarator(FD, T); return true; } bool UnionToStructCollectionVisitor::VisitRecordDecl(RecordDecl *RD) { if (RD->isUnion() && !ConsumerInstance->isInIncludedFile(RD)) ConsumerInstance->addOneRecord(RD); return true; } bool UnionToStructCollectionVisitor::VisitDeclStmt(DeclStmt *DS) { for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { if (VarDecl *CurrVD = dyn_cast(*I)) ConsumerInstance->VarToDeclStmt[CurrVD] = DS; } return true; } void UnionToStruct::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new UnionToStructCollectionVisitor(this); } bool UnionToStruct::HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) { if (VarDecl *VD = dyn_cast(*I)) VarToDeclGroup[VD] = D; CollectionVisitor->TraverseDecl(*I); } return true; } void UnionToStruct::HandleTranslationUnit(ASTContext &Ctx) { doAnalysis(); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(TheRecordDecl && "Cannot have NULL TheRecordDecl!"); TransAssert(TheDeclaratorSet && "Cannot have NULL TheDeclaratorSet!"); rewriteRecordDecls(); rewriteDeclarators(); Ctx.getDiagnostics().setSuppressAllDiagnostics(false); if (Ctx.getDiagnostics().hasErrorOccurred() || Ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } bool UnionToStruct::isValidRecordDecl(const RecordDecl *RD) { if (!RD->isCompleteDefinition()) return false; if (RD->isAnonymousStructOrUnion()) return false; for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { const FieldDecl *FD = (*I); const Type *FDTy = FD->getType().getTypePtr(); if (!FDTy->isScalarType()) return false; } return true; } void UnionToStruct::doAnalysis(void) { for (RecordDeclToDeclaratorDeclMap::iterator I = RecordToDeclarator.begin(), E = RecordToDeclarator.end(); I != E; ++I) { ValidInstanceNum++; if (ValidInstanceNum == TransformationCounter) { // TheRecordDecl = ((*I).first)->getDefinition(); TheRecordDecl = (*I).first; TheDeclaratorSet = (*I).second; } } } void UnionToStruct::rewriteOneRecordDecl(const RecordDecl *RD) { TransAssert(RD && "NULL RecordDecl!"); RewriteHelper->replaceUnionWithStruct(RD); } void UnionToStruct::rewriteRecordDecls(void) { const RecordDecl *RD = dyn_cast(TheRecordDecl->getCanonicalDecl()); TransAssert(RD && "NULL RecordDecl!"); for(RecordDecl::redecl_iterator I = RD->redecls_begin(), E = RD->redecls_end(); I != E; ++I) { rewriteOneRecordDecl(dyn_cast(*I)); } } void UnionToStruct::rewriteOneFieldDecl(const FieldDecl *FD) { const DeclContext *Ctx = TheRecordDecl->getLexicalParent(); // Skip the case where we have: // struct { // union U { // int f; // } f1, f2; // }; // union U is handled by rewriteOneRecordDecl; if (!dyn_cast(Ctx)) RewriteHelper->replaceUnionWithStruct(FD); } void UnionToStruct::getInitStrWithPointerType(const Expr *Exp, std::string &Str) { std::string ExprStr(""); RewriteHelper->getExprString(Exp, ExprStr); RecordDecl::field_iterator I = TheRecordDecl->field_begin(); RecordDecl::field_iterator E = TheRecordDecl->field_end(); TransAssert((I != E) && "Empty RecordDecl!"); Str = ExprStr; ++I; if (I == E) return; QualType ETy = Exp->getType().getCanonicalType(); for (; I != E; ++I) { Str += ","; const FieldDecl *FD = (*I); QualType FTy = FD->getType().getCanonicalType(); if (ETy == FTy) Str += ExprStr; else Str += "0"; } } void UnionToStruct::getInitStrWithNonPointerType(const Expr *Exp, std::string &Str) { std::string ExprStr(""); RewriteHelper->getExprString(Exp, ExprStr); RecordDecl::field_iterator I = TheRecordDecl->field_begin(); RecordDecl::field_iterator E = TheRecordDecl->field_end(); TransAssert((I != E) && "Empty RecordDecl!"); Str = ExprStr; ++I; if (I == E) return; for (; I != E; ++I) { Str += ","; const FieldDecl *FD = (*I); const Type *FTy = FD->getType().getTypePtr(); if (FTy->isPointerType()) Str += "0"; else Str += ExprStr; } } bool UnionToStruct::isTheFirstDecl(const VarDecl *VD) { // always return false if VD is declared in a LinkageSpecDecl, // because the first decl should be implicitly declared union record, // which is handled by rewriteOneRecordDecl const DeclContext *Ctx = VD->getDeclContext(); if (dyn_cast(Ctx)) { return false; } DeclGroupRef DGR; if (const DeclStmt *DS = VarToDeclStmt[VD]) DGR = DS->getDeclGroup(); else DGR = VarToDeclGroup[VD]; TransAssert(!DGR.isNull() && "Bad DeclRefGroup!"); if (DGR.isSingleDecl()) return true; DeclGroupRef::const_iterator I = DGR.begin(); const VarDecl *FirstVD = dyn_cast(*I); if (!FirstVD) return false; return (VD == FirstVD); } void UnionToStruct::rewriteOneVarDecl(const VarDecl *VD) { if (dyn_cast(VD)) { RewriteHelper->replaceUnionWithStruct(VD); return; } // If the first decl is RecordDecl, it will be handled // by rewriteOneRecordDecl. if (isTheFirstDecl(VD)) RewriteHelper->replaceUnionWithStruct(VD); const Type *VDTy = VD->getType().getTypePtr(); if (!VD->hasInit()) return; if (const ArrayType *ArrayTy = dyn_cast(VDTy)) { VDTy = getArrayBaseElemType(ArrayTy); // We remove the initializer for an array of unions if (!VDTy->isUnionType()) { return; } const Expr *IE = VD->getInit(); const InitListExpr *ILE = dyn_cast(IE); if (!ILE) return; // handle a special case where we have code like this: // union U a[][1] = {}; // In this case, it's safe to keep the empty initializer if (!ILE->getNumInits()) return; RewriteHelper->removeVarInitExpr(VD); return; } if (!VDTy->isUnionType()) { return; } const Expr *IE = VD->getInit(); // Looks like we are safe to skip this // e.g. // union U { int x; }; // void foo() { U y; } if (dyn_cast(IE)) return; if (!isValidRecordDecl(TheRecordDecl)) { RewriteHelper->removeVarInitExpr(VD); return; } if (const InitListExpr *ILE = dyn_cast(IE)) { if (ILE->getNumInits() != 1) { RewriteHelper->removeVarInitExpr(VD); return; } const Expr *FirstE = ILE->getInit(0); const Type *ExprTy = FirstE->getType().getTypePtr(); std::string NewInitStr; if (ExprTy->isPointerType()) { getInitStrWithPointerType(FirstE, NewInitStr); } else { getInitStrWithNonPointerType(FirstE, NewInitStr); } RewriteHelper->replaceExpr(FirstE, NewInitStr); } } void UnionToStruct::rewriteOneFunctionDecl(const FunctionDecl *FD) { RewriteHelper->replaceUnionWithStruct(FD); } void UnionToStruct::rewriteDeclarators(void) { for (DeclaratorDeclSet::const_iterator I = TheDeclaratorSet->begin(), E = TheDeclaratorSet->end(); I != E; ++I) { if (const FieldDecl *FD = dyn_cast(*I)) { rewriteOneFieldDecl(FD); continue; } if (const FunctionDecl *FunD = dyn_cast(*I)) { rewriteOneFunctionDecl(FunD); continue; } const VarDecl *VD = dyn_cast(*I); TransAssert(VD && "Invalid Declarator kind!"); rewriteOneVarDecl(VD); } } void UnionToStruct::addOneDeclarator(const DeclaratorDecl *DD, const Type *T) { if (isInIncludedFile(DD)) return; if (const ArrayType *ArrayTy = dyn_cast(T)) T = getArrayBaseElemType(ArrayTy); if (T->isPointerType()) T = getBasePointerElemType(T); if (!T->isUnionType()) return; if (T->getTypeClass() == Type::Typedef) return; const RecordType *RDTy = T->getAsUnionType(); TransAssert(RDTy && "Bad RecordType!"); if (RDTy->isIncompleteType()) return; const RecordDecl *RD = RDTy->getDecl(); const RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); TransAssert(CanonicalRD && "NULL CanonicalRD!"); if (CanonicalRD->getNameAsString() == "") { // this is a special case where we declare an unnamed union // along with a function declaration. In this case, the DDSet // for the RecordDecl hasn't been created, so we do it here. // Also, because the routine for rewriting the RecordDecl will replace // the unoin keywork, we don't need to keep DD in the DDSet. addOneRecord(CanonicalRD); return; } DeclaratorDeclSet *DDSet = RecordToDeclarator[CanonicalRD]; // It's possible that we missed CanonicalRD in malformed code. if (DDSet == nullptr) { DDSet = addOneRecord(CanonicalRD); } DDSet->insert(DD); } UnionToStruct::DeclaratorDeclSet *UnionToStruct::addOneRecord(const RecordDecl *RD) { const RecordDecl *CanonicalRD = dyn_cast(RD->getCanonicalDecl()); TransAssert(CanonicalRD && "NULL CanonicalRD!"); DeclaratorDeclSet *DDSet = RecordToDeclarator[CanonicalRD]; if (DDSet) return DDSet; DDSet = new DeclaratorDeclSet(); TransAssert(DDSet && "Member allocation failure!"); RecordToDeclarator[CanonicalRD] = DDSet; return DDSet; } UnionToStruct::~UnionToStruct(void) { delete CollectionVisitor; for (RecordDeclToDeclaratorDeclMap::iterator I = RecordToDeclarator.begin(), E = RecordToDeclarator.end(); I != E; ++I) { delete (*I).second; } } cvise-2.3.0/clang_delta/UnionToStruct.h000066400000000000000000000053621402162750500200430ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2012, 2016, 2019 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef UNION_TO_STRUCT_H #define UNION_TO_STRUCT_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "Transformation.h" namespace clang { class DeclGroupRef; class ASTContext; class DeclaratorDecl; class VarDecl; class RecordDecl; class DeclStmt; class FieldDecl; } class UnionToStructCollectionVisitor; class UnionToStruct : public Transformation { friend class UnionToStructCollectionVisitor; public: UnionToStruct(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(NULL), TheRecordDecl(NULL), TheDeclaratorSet(NULL) { } ~UnionToStruct(void); private: typedef llvm::SmallPtrSet DeclaratorDeclSet; typedef llvm::DenseMap VarToDeclStmtMap; typedef llvm::DenseMap VarToDeclGroupMap; typedef llvm::MapVector RecordDeclToDeclaratorDeclMap; virtual void Initialize(clang::ASTContext &context); virtual bool HandleTopLevelDecl(clang::DeclGroupRef D); virtual void HandleTranslationUnit(clang::ASTContext &Ctx); void addOneDeclarator(const clang::DeclaratorDecl *VD, const clang::Type *T); DeclaratorDeclSet *addOneRecord(const clang::RecordDecl *RD); void doAnalysis(void); bool isValidRecordDecl(const clang::RecordDecl *RD); void rewriteRecordDecls(void); void rewriteDeclarators(void); void rewriteOneRecordDecl(const clang::RecordDecl *RD); void rewriteOneVarDecl(const clang::VarDecl *VD); void rewriteOneFieldDecl(const clang::FieldDecl *FD); void rewriteOneFunctionDecl(const clang::FunctionDecl *FD); void getInitStrWithPointerType(const clang::Expr *E, std::string &Str); void getInitStrWithNonPointerType(const clang::Expr *E, std::string &Str); bool isTheFirstDecl(const clang::VarDecl *VD); VarToDeclStmtMap VarToDeclStmt; VarToDeclGroupMap VarToDeclGroup; RecordDeclToDeclaratorDeclMap RecordToDeclarator; UnionToStructCollectionVisitor *CollectionVisitor; const clang::RecordDecl *TheRecordDecl; DeclaratorDeclSet *TheDeclaratorSet; // Unimplemented UnionToStruct(void); UnionToStruct(const UnionToStruct &); void operator=(const UnionToStruct &); }; #endif cvise-2.3.0/clang_delta/VectorToArray.cpp000066400000000000000000000133341402162750500203400ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // Copyright (c) 2016, 2019 The University of Utah // Copyright (c) 2016 Ori Brostovski // Copyright (c) 2016 Ceemple Software Ltd // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// // Here is a quick command line for testing: // ./clang_delta --transformation=vector-to-array ~/empty.cpp // --counter=1./clang_delta --transformation=vector-to-array ~/empty.cpp // --counter=1 // TODO: // pointer/array of vector // dependent type vector // vector used before class definition (lesser priotity, not common) // vector not inside std:: // all scopes, global, static, member, local, threadsafe, whatever // vector class without params // other templates not changed #if HAVE_CONFIG_H # include #endif #include "VectorToArray.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceManager.h" #include "TransformationManager.h" #include #define ARRAY_SUFFIX "[10]" using namespace clang; static const char *DescriptionMsg = "Try replacing vectors with arrays. It transforms the following code: \n\ vector v' \n\ to \n\ int v[10]\n"; static RegisterTransformation Trans("vector-to-array", DescriptionMsg); class VectorToArrayCollectionVisitor : public RecursiveASTVisitor { public: explicit VectorToArrayCollectionVisitor(VectorToArray *Instance) : Consumer(Instance) {} bool VisitNamedDecl(NamedDecl *D) { return true; } bool VisitClassTemplateDecl(ClassTemplateDecl *D) { if (Consumer->isInIncludedFile(D)) return true; auto *NS = dyn_cast(D->getDeclContext()); if (!NS) return true; if (NS->getName() != "std") return true; if (!dyn_cast(NS->getDeclContext())) return true; if (!D->isThisDeclarationADefinition()) return true; if (D->getName() != "vector") return true; Consumer->TheVectorDecl = D; return true; } bool VisitVarDecl(VarDecl *D) { if (Consumer->isInIncludedFile(D)) return true; const Type *Ty = D->getType().getTypePtr(); if (!Ty) return true; CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl(); if (!CXXRD) return true; CXXRecordDecl *CXXRDT = CXXRD->getTemplateInstantiationPattern(); if (!CXXRDT) return true; ClassTemplateDecl *CTD = CXXRDT->getDescribedClassTemplate(); while (CTD && !CTD->isThisDeclarationADefinition()) { CTD = CTD->getPreviousDecl(); } if (!CTD || CTD != Consumer->TheVectorDecl) return true; ++Consumer->ValidInstanceNum; if (Consumer->ValidInstanceNum == Consumer->TransformationCounter) Consumer->TheVarDecl = D; return true; } private: VectorToArray *Consumer; }; class VectorToArrayRewriteVisitor : public RecursiveASTVisitor { private: std::string getVectorElemTypeName(VarDecl *VD) { CXXRecordDecl *CXXRD = VD->getType().getTypePtr()->getAsCXXRecordDecl(); auto CTSD = dyn_cast(CXXRD); const TemplateArgument &TmplArg = CTSD->getTemplateArgs()[0]; return TmplArg.getAsType().getAsString(); } public: bool VisitVarDecl(VarDecl *VD) { if (VD != Consumer->TheVarDecl) return true; Rewriter &TheRewriter = Consumer->TheRewriter; const SourceManager &SM = TheRewriter.getSourceMgr(); SourceLocation NameLoc = VD->getLocation(); IdentifierInfo *IdInfo = VD->getIdentifier(); assert(IdInfo && "Nameless variable"); unsigned NameLength = IdInfo->getLength(); assert(NameLength && "Variable name has no length"); SourceLocation TypeLocStart = VD->getBeginLoc(); const std::string ElemTypeName = getVectorElemTypeName(VD); SourceLocation NameLocM1 = NameLoc.getLocWithOffset(-1); bool isInvalid = false; const char *charBeforeName = SM.getCharacterData(NameLocM1, &isInvalid); assert(!isInvalid && "failed to get char before name"); TheRewriter.ReplaceText(NameLoc.getLocWithOffset(NameLength), 0, ARRAY_SUFFIX); if (!std::isspace(*charBeforeName)) TheRewriter.InsertText(NameLoc, " "); TheRewriter.ReplaceText(SourceRange(TypeLocStart, NameLocM1), ElemTypeName); return true; } explicit VectorToArrayRewriteVisitor(VectorToArray *Cons) : Consumer(Cons) {} private: VectorToArray *Consumer; }; VectorToArray::~VectorToArray() { delete RewriteVisitor; delete CollectionVisitor; } void VectorToArray::Initialize(ASTContext &ctx) { Transformation::Initialize(ctx); CollectionVisitor = new VectorToArrayCollectionVisitor(this); RewriteVisitor = new VectorToArrayRewriteVisitor(this); } void VectorToArray::HandleTranslationUnit(ASTContext &ctx) { CollectionVisitor->TraverseDecl(ctx.getTranslationUnitDecl()); if (QueryInstanceOnly) return; if (TransformationCounter > ValidInstanceNum) { TransError = TransMaxInstanceError; return; } TransAssert(RewriteVisitor && "NULL RewriteVisitor!"); TransAssert(TheVectorDecl && "NULL TheRecordDecl!"); TransAssert(TheVarDecl && "NULL TheVarDecl!"); // RewriteVisitor->TraverseDecl(ctx.getTranslationUnitDecl()); // ORI NOTE: This is much more efficient, but will not work if we want // xto do more than one change RewriteVisitor->VisitVarDecl(TheVarDecl); if (ctx.getDiagnostics().hasErrorOccurred() || ctx.getDiagnostics().hasFatalErrorOccurred()) TransError = TransInternalError; } cvise-2.3.0/clang_delta/VectorToArray.h000066400000000000000000000025751402162750500200120ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // Copyright (c) 2016 The University of Utah // Copyright (c) 2016 Ori Brostovski // Copyright (c) 2016 Ceemple Software Ltd // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef VECTOR_TO_ARRAY_H #define VECTOR_TO_ARRAY_H #include "Transformation.h" class VectorToArrayCollectionVisitor; class VectorToArrayRewriteVisitor; class VectorToArray : public Transformation { friend class VectorToArrayCollectionVisitor; friend class VectorToArrayRewriteVisitor; public: VectorToArray(const char *TransName, const char *Desc) : Transformation(TransName, Desc), CollectionVisitor(nullptr), RewriteVisitor(nullptr) {} ~VectorToArray(); private: virtual void Initialize(clang::ASTContext &context); virtual void HandleTranslationUnit(clang::ASTContext &ctx); void simplifyVectorToArray(); VectorToArrayCollectionVisitor *CollectionVisitor; VectorToArrayRewriteVisitor *RewriteVisitor; clang::ClassTemplateDecl *TheVectorDecl; clang::VarDecl *TheVarDecl; // Unimplemented VectorToArray(); VectorToArray(const VectorToArray &); void operator=(const VectorToArray &); }; #endif cvise-2.3.0/clang_delta/git_version.cpp.in000066400000000000000000000007341402162750500205310ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #if HAVE_CONFIG_H # include #endif #include "git_version.h" const char git_version[] = "@GIT_HASH@"; cvise-2.3.0/clang_delta/git_version.h000066400000000000000000000007201402162750500175640ustar00rootroot00000000000000//===----------------------------------------------------------------------===// // // Copyright (c) 2016 The University of Utah // All rights reserved. // // This file is distributed under the University of Illinois Open Source // License. See the file COPYING for details. // //===----------------------------------------------------------------------===// #ifndef GIT_VERSION_H #define GIT_VERSION_H extern const char git_version[]; #endif // GIT_VERSION_H cvise-2.3.0/clang_delta/tests/000077500000000000000000000000001402162750500162265ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/000077500000000000000000000000001402162750500220375ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/cast.c000066400000000000000000000001371402162750500231360ustar00rootroot00000000000000int a1[10]; void foo() { char a; int t = 1; ((char (*)[t]) a)[0][0] = 0; a1[1] = 1; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/cast.output000066400000000000000000000001501402162750500242470ustar00rootroot00000000000000int a1[10]; int a1_1; void foo() { char a; int t = 1; ((char (*)[t]) a)[0][0] = 0; a1_1 = 1; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test1.c000066400000000000000000000000561402162750500232440ustar00rootroot00000000000000int a[1], b; int foo(void) { return a[0]; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test1.output000066400000000000000000000000661402162750500243630ustar00rootroot00000000000000int a[1], b; int a_0; int foo(void) { return a_0; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test2.c000066400000000000000000000001101402162750500232340ustar00rootroot00000000000000struct S { int f1; } a, b[1]; int foo() { return a.f1 + b[0].f1; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test2.output000066400000000000000000000001201402162750500243530ustar00rootroot00000000000000struct S { int f1; } a, b[1]; int a_0; int foo() { return a_0 + b[0].f1; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test3.c000066400000000000000000000001201402162750500232360ustar00rootroot00000000000000struct S { int a[2]; }; int foo() { struct S s = {1,2}; return s.a[0]; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test3.output000066400000000000000000000001401402162750500243560ustar00rootroot00000000000000struct S { int a[2]; }; int foo() { struct S s = {1,2}; int s_0_0 = 1; return s_0_0; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test4.c000066400000000000000000000001421402162750500232430ustar00rootroot00000000000000struct S { int f1; int f2; }; struct S s = { .f1 = 0, .f2 = 16 }; void foo() { s.f1++; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test4.output000066400000000000000000000001561402162750500243660ustar00rootroot00000000000000struct S { int f1; int f2; }; struct S s = { .f1 = 0, .f2 = 16 }; int s_0 = 0; void foo() { s_0++; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test5.cc000066400000000000000000000001211402162750500234040ustar00rootroot00000000000000extern "C" { extern char *gnu_optarg; } char foo() { return gnu_optarg[0]; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test5.output000066400000000000000000000001431402162750500243630ustar00rootroot00000000000000extern "C" { extern char *gnu_optarg; char gnu_optarg_0; } char foo() { return gnu_optarg_0; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test6.cc000066400000000000000000000001351402162750500234120ustar00rootroot00000000000000struct S { int **f1; }; void foo() { int *a[16]; struct S s = { a }; s.f1[0] = 0; } cvise-2.3.0/clang_delta/tests/aggregate-to-scalar/test6.output000066400000000000000000000001511402162750500243630ustar00rootroot00000000000000struct S { int **f1; }; void foo() { int *a[16]; struct S s = { a }; int *s_0_0; s_0_0 = 0; } cvise-2.3.0/clang_delta/tests/callexpr-to-value/000077500000000000000000000000001402162750500215725ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/callexpr-to-value/macro1.c000066400000000000000000000001521402162750500231160ustar00rootroot00000000000000#define macro bar(1,2) int bar(int p1, int p2) { return p1 + p2; } void foo(void) { int x = macro; } cvise-2.3.0/clang_delta/tests/callexpr-to-value/macro1.output000066400000000000000000000001461402162750500242370ustar00rootroot00000000000000#define macro bar(1,2) int bar(int p1, int p2) { return p1 + p2; } void foo(void) { int x = 0; } cvise-2.3.0/clang_delta/tests/callexpr-to-value/macro2.c000066400000000000000000000000431402162750500231160ustar00rootroot00000000000000#define b(a) a c() { d b((d)); } cvise-2.3.0/clang_delta/tests/callexpr-to-value/macro2.output000066400000000000000000000000341402162750500242340ustar00rootroot00000000000000#define b(a) a c() { 0; } cvise-2.3.0/clang_delta/tests/callexpr-to-value/test1.c000066400000000000000000000000711402162750500227740ustar00rootroot00000000000000float a; int b[__builtin_classify_type(a) == 9 ? 1 : 2]; cvise-2.3.0/clang_delta/tests/callexpr-to-value/test1.output000066400000000000000000000000401402162750500241060ustar00rootroot00000000000000float a; int b[0 == 9 ? 1 : 2]; cvise-2.3.0/clang_delta/tests/callexpr-to-value/test2.c000066400000000000000000000000411402162750500227720ustar00rootroot00000000000000#define a(b) (b) c() { d a(0); } cvise-2.3.0/clang_delta/tests/callexpr-to-value/test2.output000066400000000000000000000000341402162750500241120ustar00rootroot00000000000000#define a(b) (b) c() { 0; } cvise-2.3.0/clang_delta/tests/copy-propagation/000077500000000000000000000000001402162750500215215ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/copy-propagation/copy1.cpp000066400000000000000000000001711402162750500232570ustar00rootroot00000000000000struct S { S() { int t1; int a; int b = a; { m; int a = b; t1 = a; } } int m; }; cvise-2.3.0/clang_delta/tests/copy-propagation/copy1.output000066400000000000000000000001711402162750500240350ustar00rootroot00000000000000struct S { S() { int t1; int a; int b = a; { m; int a = a; t1 = a; } } int m; }; cvise-2.3.0/clang_delta/tests/copy-propagation/copy2.cpp000066400000000000000000000001711402162750500232600ustar00rootroot00000000000000struct S { S() { int t1; int a; int b = a; { m; int a = b; t1 = a; } } int m; }; cvise-2.3.0/clang_delta/tests/copy-propagation/copy2.output000066400000000000000000000001711402162750500240360ustar00rootroot00000000000000struct S { S() { int t1; int a; int b = a; { m; int a = b; t1 = b; } } int m; }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/000077500000000000000000000000001402162750500221165ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct.cpp000066400000000000000000000000411402162750500252750ustar00rootroot00000000000000struct S { void foo(); }; S s; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct.output000066400000000000000000000000101402162750500260470ustar00rootroot00000000000000 int s; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct2.cpp000066400000000000000000000000561402162750500253650ustar00rootroot00000000000000struct S1 { struct {} S; struct S *s1; }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct2.output000066400000000000000000000000511402162750500261360ustar00rootroot00000000000000struct S1 { int S; struct S *s1; }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct3.cpp000066400000000000000000000000561402162750500253660ustar00rootroot00000000000000struct S1 { struct {} S; struct S *s1; }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct3.output000066400000000000000000000000521402162750500261400ustar00rootroot00000000000000struct S1 { struct {} S; int *s1; }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct4.cpp000066400000000000000000000000271402162750500253650ustar00rootroot00000000000000struct S {} g, i; S s; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct4.output000066400000000000000000000000231402162750500261370ustar00rootroot00000000000000 int g, i; int s; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct5.cpp000066400000000000000000000000541402162750500253660ustar00rootroot00000000000000struct S2 { char a[2]; }; S2 s = {{1,2}}; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct5.output000066400000000000000000000000141402162750500261400ustar00rootroot00000000000000 int s = 0; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct6.c000066400000000000000000000000221402162750500250220ustar00rootroot00000000000000struct {}a = {}; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct6.output000066400000000000000000000000001402162750500261340ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct7.c000066400000000000000000000000501402162750500250240ustar00rootroot00000000000000struct S { void (*x) (struct S *); }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/empty-struct7.output000066400000000000000000000000011402162750500261360ustar00rootroot00000000000000 cvise-2.3.0/clang_delta/tests/empty-struct-to-int/struct_int.c000066400000000000000000000000771402162750500244640ustar00rootroot00000000000000struct { int f1; struct { int f2; } f3[]; } s1 = {}; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/struct_int.output000066400000000000000000000000531402162750500255740ustar00rootroot00000000000000struct { int f1; int f3[]; } s1 = {}; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/test1.cc000066400000000000000000000000271402162750500234640ustar00rootroot00000000000000struct S{}; S s1, s2; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/test1.output000066400000000000000000000000161402162750500244350ustar00rootroot00000000000000 int s1, s2; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/test2.cc000066400000000000000000000000551402162750500234660ustar00rootroot00000000000000struct S{}; struct S1 : S {}; struct S3 {}; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/test2.output000066400000000000000000000000401402162750500244330ustar00rootroot00000000000000struct S{}; struct S1 : S {}; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/test3.c000066400000000000000000000000571402162750500233260ustar00rootroot00000000000000struct S; struct S *s; struct S { int i; }; cvise-2.3.0/clang_delta/tests/empty-struct-to-int/test3.output000066400000000000000000000000141402162750500244350ustar00rootroot00000000000000 int *s; cvise-2.3.0/clang_delta/tests/instantiate-template-param/000077500000000000000000000000001402162750500234605ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/instantiate-template-param/default_param.cc000066400000000000000000000001451402162750500265730ustar00rootroot00000000000000template struct A { void bar(T2 p); }; void foo() { A a; } cvise-2.3.0/clang_delta/tests/instantiate-template-param/default_param.output000066400000000000000000000001461402162750500275470ustar00rootroot00000000000000template struct A { void bar(int p); }; void foo() { A a; } cvise-2.3.0/clang_delta/tests/instantiate-template-param/test1.cc000066400000000000000000000001411402162750500250230ustar00rootroot00000000000000template struct S { T bar(T p) { return p; } }; void foo() { struct S s; } cvise-2.3.0/clang_delta/tests/instantiate-template-param/test1.output000066400000000000000000000001451402162750500260020ustar00rootroot00000000000000template struct S { int bar(int p) { return p; } }; void foo() { struct S s; } cvise-2.3.0/clang_delta/tests/instantiate-template-param/test2.cc000066400000000000000000000003531402162750500250310ustar00rootroot00000000000000template class A { public: template struct C { typedef A other; }; }; template class B { typedef typename T2::template C::other type; }; class B >; cvise-2.3.0/clang_delta/tests/instantiate-template-param/test2.output000066400000000000000000000003601402162750500260020ustar00rootroot00000000000000template class A { public: template struct C { typedef A other; }; }; template class B { typedef typename A::template C::other type; }; class B >; cvise-2.3.0/clang_delta/tests/instantiate-template-param/test3.cc000066400000000000000000000001531402162750500250300ustar00rootroot00000000000000template struct S { T bar(T p) { return p; } }; class T {}; void foo() { struct S s; } cvise-2.3.0/clang_delta/tests/local-to-global/000077500000000000000000000000001402162750500211765ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/local-to-global/macro.c000066400000000000000000000000711402162750500224410ustar00rootroot00000000000000#define TYPE unsigned short int void foo() { TYPE t; } cvise-2.3.0/clang_delta/tests/local-to-global/macro.output000066400000000000000000000001101402162750500235510ustar00rootroot00000000000000#define TYPE unsigned short int unsigned short foo_t; void foo() { } cvise-2.3.0/clang_delta/tests/local-to-global/unnamed_1.c000066400000000000000000000000341402162750500232060ustar00rootroot00000000000000void f() { struct S *s; } cvise-2.3.0/clang_delta/tests/local-to-global/unnamed_1.output000066400000000000000000000000371402162750500243270ustar00rootroot00000000000000struct S *f_s; void f() { } cvise-2.3.0/clang_delta/tests/local-to-global/unnamed_2.c000066400000000000000000000000671402162750500232150ustar00rootroot00000000000000void f() { union { int j; } l; long i = 1; } cvise-2.3.0/clang_delta/tests/local-to-global/unnamed_2.output000066400000000000000000000000721402162750500243270ustar00rootroot00000000000000union { int j; } f_l; void f() { long i = 1; } cvise-2.3.0/clang_delta/tests/local-to-global/unnamed_3.c000066400000000000000000000001141402162750500232070ustar00rootroot00000000000000void f() { long i = ({ union { int j; } l; l.j; }); } cvise-2.3.0/clang_delta/tests/local-to-global/unnamed_3.output000066400000000000000000000001211402162750500243230ustar00rootroot00000000000000union { int j; } f_l; void f() { long i = ({ f_l.j; }); } cvise-2.3.0/clang_delta/tests/param-to-global/000077500000000000000000000000001402162750500212045ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/param-to-global/macro.c000066400000000000000000000000651402162750500224520ustar00rootroot00000000000000#define TYPE unsigned short int void foo(TYPE p) { } cvise-2.3.0/clang_delta/tests/param-to-global/macro.output000066400000000000000000000001111402162750500235600ustar00rootroot00000000000000#define TYPE unsigned short int unsigned short foo_p; void foo(void) { } cvise-2.3.0/clang_delta/tests/reduce-array-dim/000077500000000000000000000000001402162750500213605ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/reduce-array-dim/non-type-temp-arg.cpp000066400000000000000000000001151402162750500253440ustar00rootroot00000000000000template void foo() { double k[1][h]; } void bar() { foo<1>(); } cvise-2.3.0/clang_delta/tests/reduce-array-dim/non-type-temp-arg.output000066400000000000000000000001121402162750500261170ustar00rootroot00000000000000template void foo() { double k[1]; } void bar() { foo<1>(); } cvise-2.3.0/clang_delta/tests/reduce-pointer-level/000077500000000000000000000000001402162750500222605ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/reduce-pointer-level/scalar-init-expr.cpp000066400000000000000000000000661402162750500261500ustar00rootroot00000000000000struct S { typedef char *c; S() { c i = c(); } }; cvise-2.3.0/clang_delta/tests/reduce-pointer-level/scalar-init-expr.output000066400000000000000000000000651402162750500267250ustar00rootroot00000000000000struct S { typedef char c; S() { c i = c(); } }; cvise-2.3.0/clang_delta/tests/remove-enum-member-value/000077500000000000000000000000001402162750500230445ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-enum-member-value/builtin_macro.c000066400000000000000000000000541402162750500260360ustar00rootroot00000000000000typedef enum E { a = __ATOMIC_RELAXED, }; cvise-2.3.0/clang_delta/tests/remove-enum-member-value/builtin_macro.output000066400000000000000000000000321402162750500271500ustar00rootroot00000000000000typedef enum E { a , }; cvise-2.3.0/clang_delta/tests/remove-namespace/000077500000000000000000000000001402162750500214555ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-namespace/macro.cpp000066400000000000000000000005661402162750500232710ustar00rootroot00000000000000#define BEGIN_NAMESPACE namespace ns { #define END_NAMESPACE } BEGIN_NAMESPACE int foo(); END_NAMESPACE #define BEGIN_NAMESPACE2 namespace ns2 { BEGIN_NAMESPACE2 int foo2(); } #define END_NAMESPACE3 } namespace ns3 { int foo3(); END_NAMESPACE3 #define BEGIN_NAMESPACE4 namespace ns4 { namespace ns5 { #define END_NAMESPACE4 } } BEGIN_NAMESPACE4 void foo4(); END_NAMESPACE4 cvise-2.3.0/clang_delta/tests/remove-namespace/macro.output000066400000000000000000000005321402162750500240400ustar00rootroot00000000000000#define BEGIN_NAMESPACE namespace ns { #define END_NAMESPACE } int foo(); #define BEGIN_NAMESPACE2 namespace ns2 { BEGIN_NAMESPACE2 int foo2(); } #define END_NAMESPACE3 } namespace ns3 { int foo3(); END_NAMESPACE3 #define BEGIN_NAMESPACE4 namespace ns4 { namespace ns5 { #define END_NAMESPACE4 } } BEGIN_NAMESPACE4 void foo4(); END_NAMESPACE4 cvise-2.3.0/clang_delta/tests/remove-namespace/macro.output2000066400000000000000000000005451402162750500241260ustar00rootroot00000000000000#define BEGIN_NAMESPACE namespace ns { #define END_NAMESPACE } BEGIN_NAMESPACE int foo(); END_NAMESPACE #define BEGIN_NAMESPACE2 namespace ns2 { int foo2(); #define END_NAMESPACE3 } namespace ns3 { int foo3(); END_NAMESPACE3 #define BEGIN_NAMESPACE4 namespace ns4 { namespace ns5 { #define END_NAMESPACE4 } } BEGIN_NAMESPACE4 void foo4(); END_NAMESPACE4 cvise-2.3.0/clang_delta/tests/remove-namespace/macro.output3000066400000000000000000000005311402162750500241220ustar00rootroot00000000000000#define BEGIN_NAMESPACE namespace ns { #define END_NAMESPACE } BEGIN_NAMESPACE int foo(); END_NAMESPACE #define BEGIN_NAMESPACE2 namespace ns2 { BEGIN_NAMESPACE2 int foo2(); } #define END_NAMESPACE3 } int foo3(); #define BEGIN_NAMESPACE4 namespace ns4 { namespace ns5 { #define END_NAMESPACE4 } } BEGIN_NAMESPACE4 void foo4(); END_NAMESPACE4 cvise-2.3.0/clang_delta/tests/remove-namespace/macro.output4000066400000000000000000000005301402162750500241220ustar00rootroot00000000000000#define BEGIN_NAMESPACE namespace ns { #define END_NAMESPACE } BEGIN_NAMESPACE int foo(); END_NAMESPACE #define BEGIN_NAMESPACE2 namespace ns2 { BEGIN_NAMESPACE2 int foo2(); } #define END_NAMESPACE3 } namespace ns3 { int foo3(); END_NAMESPACE3 #define BEGIN_NAMESPACE4 namespace ns4 { namespace ns5 { #define END_NAMESPACE4 } } void foo4(); cvise-2.3.0/clang_delta/tests/remove-namespace/macro.output5000066400000000000000000000005301402162750500241230ustar00rootroot00000000000000#define BEGIN_NAMESPACE namespace ns { #define END_NAMESPACE } BEGIN_NAMESPACE int foo(); END_NAMESPACE #define BEGIN_NAMESPACE2 namespace ns2 { BEGIN_NAMESPACE2 int foo2(); } #define END_NAMESPACE3 } namespace ns3 { int foo3(); END_NAMESPACE3 #define BEGIN_NAMESPACE4 namespace ns4 { namespace ns5 { #define END_NAMESPACE4 } } void foo4(); cvise-2.3.0/clang_delta/tests/remove-namespace/namespace.cpp000066400000000000000000000004001402162750500241070ustar00rootroot00000000000000namespace NS1 { namespace NS2 { template T foo(T p1, T p2); template T operator+(T p1, T p2); int func(); } } namespace NS3 { struct S {}; S s1, s2; using namespace NS1::NS2; int bar() { func(); return 0; } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace.output000066400000000000000000000003531402162750500246740ustar00rootroot00000000000000 namespace NS2 { template T foo(T p1, T p2); template T operator+(T p1, T p2); int func(); } namespace NS3 { struct S {}; S s1, s2; using namespace NS2; int bar() { func(); return 0; } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace.output2000066400000000000000000000003531402162750500247560ustar00rootroot00000000000000namespace NS1 { template T foo(T p1, T p2); template T operator+(T p1, T p2); int func(); } namespace NS3 { struct S {}; S s1, s2; using namespace NS1; int bar() { func(); return 0; } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace.output3000066400000000000000000000003411402162750500247540ustar00rootroot00000000000000namespace NS1 { namespace NS2 { template T foo(T p1, T p2); template T operator+(T p1, T p2); int func(); } } struct S {}; S s1, s2; int bar() { NS1::NS2::func(); return 0; } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace10.cpp000066400000000000000000000000741402162750500242570ustar00rootroot00000000000000namespace NS { namespace { int x; } // ANON } // NS cvise-2.3.0/clang_delta/tests/remove-namespace/namespace10.output000066400000000000000000000000551402162750500250340ustar00rootroot00000000000000 namespace { int x; } // ANON // NS cvise-2.3.0/clang_delta/tests/remove-namespace/namespace10.output2000066400000000000000000000000601402162750500251120ustar00rootroot00000000000000namespace NS { int x; // ANON } // NS cvise-2.3.0/clang_delta/tests/remove-namespace/namespace11.cpp000066400000000000000000000002421402162750500242550ustar00rootroot00000000000000namespace NS1 { void foo() {} void fiz() {} } // NS1 namespace NS2 { using namespace NS1; int bar() { foo(); } } // NS2 void fiz() {} void f() { fiz(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace11.output000066400000000000000000000002131402162750500250310ustar00rootroot00000000000000 void foo() {} void Trans_NS_NS1_fiz() {} // NS1 namespace NS2 { int bar() { foo(); } } // NS2 void fiz() {} void f() { fiz(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace11.output2000066400000000000000000000002031402162750500251120ustar00rootroot00000000000000namespace NS1 { void foo() {} void fiz() {} } // NS1 int bar() { NS1::foo(); } // NS2 void fiz() {} void f() { fiz(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace12.cpp000066400000000000000000000002501402162750500242550ustar00rootroot00000000000000namespace NS1 { } namespace NS2 { namespace NS1 { void foo() {} } // NS1 namespace NS3 { using namespace NS1; void bar() {foo();} } // NS3 } // NS2 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace12.output000066400000000000000000000002301402162750500250310ustar00rootroot00000000000000 namespace NS2 { namespace NS1 { void foo() {} } // NS1 namespace NS3 { using namespace NS1; void bar() {foo();} } // NS3 } // NS2 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace12.output2000066400000000000000000000002621402162750500251200ustar00rootroot00000000000000namespace NS1 { } namespace Trans_NS_NS2_NS1 { void foo() {} } // NS1 namespace NS3 { using namespace Trans_NS_NS2_NS1; void bar() {foo();} } // NS3 // NS2 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace12.output3000066400000000000000000000002041402162750500251150ustar00rootroot00000000000000namespace NS1 { } namespace NS2 { void foo() {} // NS1 namespace NS3 { void bar() {foo();} } // NS3 } // NS2 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace13.cpp000066400000000000000000000001701402162750500242570ustar00rootroot00000000000000namespace NS1 { namespace NS2 { void foo(); } // NS2 } // NS1 namespace cl = NS1::NS2; void bar() {cl::foo(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace13.output000066400000000000000000000001431402162750500250350ustar00rootroot00000000000000 namespace NS2 { void foo(); } // NS2 // NS1 namespace cl = NS2; void bar() {cl::foo(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace13.output2000066400000000000000000000001431402162750500251170ustar00rootroot00000000000000namespace NS1 { void foo(); // NS2 } // NS1 namespace cl = NS1; void bar() {cl::foo(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace14.cpp000066400000000000000000000001151402162750500242570ustar00rootroot00000000000000namespace NS1 { void foo(); } namespace cl = NS1; void bar() {cl::foo(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace14.output000066400000000000000000000000461402162750500250400ustar00rootroot00000000000000 void foo(); void bar() {foo(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace15.cpp000066400000000000000000000024171402162750500242670ustar00rootroot00000000000000namespace NS1 { template < typename T > struct A { typedef const T & ptype; }; template < typename T > struct B { typedef typename NS1::A < T >::ptype ptype; }; namespace NS2 { namespace NS3 { template < typename > struct C { }; struct F:C < int > { F () { } }; F const m2 = F (); C < int >m1 = C < int >(); } namespace NS3 { class G:public NS1::NS2::NS3::C < int > { public: NS1::NS2::NS3::C < int >base_t; typedef NS1::B < NS1::NS2::NS3::F >::ptype MY_T; G (MY_T p1):subj (p1) { } NS1::NS2::NS3::F subj; }; template < typename A, typename B > NS1::NS2::NS3::C < int >operator>> (C < A > const &, C < B >); template < typename A, typename B > NS1::NS2::NS3::C < int >operator| (C < A >, C < B >); template < typename A > NS1::NS2::NS3::C < int >operator| (C < A >, int); template < typename A > NS1::NS2::NS3::C < int >operator| (C < A >, char *); C < int >eps_p = C < int >(); } } } namespace cl = NS1::NS2::NS3; struct H:cl::G { H (NS1::NS2::NS3::F const &p1) : cl::G (p1) { } }; struct D { H operator[] (NS1::NS2::NS3::F const &p1) { return p1; } }; D var = D (); namespace NS1 { namespace NS2 { namespace NS3 { template < typename T > C < int > abc (T); } } } void foo () { var[cl::m2] >> cl::abc (0) >> cl::eps_p >> cl:: m1; } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace15.output000066400000000000000000000022561402162750500250460ustar00rootroot00000000000000 template < typename T > struct A { typedef const T & ptype; }; template < typename T > struct B { typedef typename A < T >::ptype ptype; }; namespace NS2 { namespace NS3 { template < typename > struct C { }; struct F:C < int > { F () { } }; F const m2 = F (); C < int >m1 = C < int >(); } namespace NS3 { class G:public NS2::NS3::C < int > { public: NS2::NS3::C < int >base_t; typedef B < NS2::NS3::F >::ptype MY_T; G (MY_T p1):subj (p1) { } NS2::NS3::F subj; }; template < typename A, typename B > NS2::NS3::C < int >operator>> (C < A > const &, C < B >); template < typename A, typename B > NS2::NS3::C < int >operator| (C < A >, C < B >); template < typename A > NS2::NS3::C < int >operator| (C < A >, int); template < typename A > NS2::NS3::C < int >operator| (C < A >, char *); C < int >eps_p = C < int >(); } } namespace cl = NS2::NS3; struct H:cl::G { H (NS2::NS3::F const &p1) : cl::G (p1) { } }; struct D { H operator[] (NS2::NS3::F const &p1) { return p1; } }; D var = D (); namespace NS2 { namespace NS3 { template < typename T > C < int > abc (T); } } void foo () { var[cl::m2] >> cl::abc (0) >> cl::eps_p >> cl:: m1; } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace15.output2000066400000000000000000000022701402162750500251240ustar00rootroot00000000000000namespace NS1 { template < typename T > struct A { typedef const T & ptype; }; template < typename T > struct B { typedef typename NS1::A < T >::ptype ptype; }; namespace NS3 { template < typename > struct C { }; struct F:C < int > { F () { } }; F const m2 = F (); C < int >m1 = C < int >(); } namespace NS3 { class G:public NS1::NS3::C < int > { public: NS1::NS3::C < int >base_t; typedef NS1::B < NS1::NS3::F >::ptype MY_T; G (MY_T p1):subj (p1) { } NS1::NS3::F subj; }; template < typename A, typename B > NS1::NS3::C < int >operator>> (C < A > const &, C < B >); template < typename A, typename B > NS1::NS3::C < int >operator| (C < A >, C < B >); template < typename A > NS1::NS3::C < int >operator| (C < A >, int); template < typename A > NS1::NS3::C < int >operator| (C < A >, char *); C < int >eps_p = C < int >(); } } namespace cl = NS1::NS3; struct H:cl::G { H (NS1::NS3::F const &p1) : cl::G (p1) { } }; struct D { H operator[] (NS1::NS3::F const &p1) { return p1; } }; D var = D (); namespace NS1 { namespace NS3 { template < typename T > C < int > abc (T); } } void foo () { var[cl::m2] >> cl::abc (0) >> cl::eps_p >> cl:: m1; } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace15.output3000066400000000000000000000022501402162750500251230ustar00rootroot00000000000000namespace NS1 { template < typename T > struct A { typedef const T & ptype; }; template < typename T > struct B { typedef typename NS1::A < T >::ptype ptype; }; namespace NS2 { template < typename > struct C { }; struct F:C < int > { F () { } }; F const m2 = F (); C < int >m1 = C < int >(); class G:public NS1::NS2::C < int > { public: NS1::NS2::C < int >base_t; typedef NS1::B < NS1::NS2::F >::ptype MY_T; G (MY_T p1):subj (p1) { } NS1::NS2::F subj; }; template < typename A, typename B > NS1::NS2::C < int >operator>> (C < A > const &, C < B >); template < typename A, typename B > NS1::NS2::C < int >operator| (C < A >, C < B >); template < typename A > NS1::NS2::C < int >operator| (C < A >, int); template < typename A > NS1::NS2::C < int >operator| (C < A >, char *); C < int >eps_p = C < int >(); } } namespace cl = NS1::NS2; struct H:cl::G { H (NS1::NS2::F const &p1) : cl::G (p1) { } }; struct D { H operator[] (NS1::NS2::F const &p1) { return p1; } }; D var = D (); namespace NS1 { namespace NS2 { template < typename T > C < int > abc (T); } } void foo () { var[cl::m2] >> cl::abc (0) >> cl::eps_p >> cl:: m1; } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace2.cpp000066400000000000000000000004331402162750500241770ustar00rootroot00000000000000namespace NS1 { template struct foo { operator long double() const; }; namespace NS2 { typedef struct { int f; } S; S bar(int); } using namespace NS2; template <> foo<32>::operator long double() const { long double t; *reinterpret_cast(&t) = bar(0); return t; } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace2.output000066400000000000000000000004061402162750500247550ustar00rootroot00000000000000 template struct foo { operator long double() const; }; namespace NS2 { typedef struct { int f; } S; NS2::S bar(int); } template <> foo<32>::operator long double() const { long double t; *reinterpret_cast(&t) = NS2::bar(0); return t; } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace2.output2000066400000000000000000000003671402162750500250450ustar00rootroot00000000000000namespace NS1 { template struct foo { operator long double() const; }; typedef struct { int f; } S; S bar(int); template <> foo<32>::operator long double() const { long double t; *reinterpret_cast(&t) = bar(0); return t; } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace3.cpp000066400000000000000000000001661402162750500242030ustar00rootroot00000000000000namespace NS1 { namespace NS2 { namespace NS3 { } // NS3 } // NS2 } // NS1 namespace c1 = NS1::NS2::NS3; cvise-2.3.0/clang_delta/tests/remove-namespace/namespace3.output000066400000000000000000000001411402162750500247520ustar00rootroot00000000000000 namespace NS2 { namespace NS3 { } // NS3 } // NS2 // NS1 namespace c1 = NS2::NS3; cvise-2.3.0/clang_delta/tests/remove-namespace/namespace3.output2000066400000000000000000000001411402162750500250340ustar00rootroot00000000000000namespace NS1 { namespace NS3 { } // NS3 // NS2 } // NS1 namespace c1 = NS1::NS3; cvise-2.3.0/clang_delta/tests/remove-namespace/namespace3.output3000066400000000000000000000001411402162750500250350ustar00rootroot00000000000000namespace NS1 { namespace NS2 { // NS3 } // NS2 } // NS1 namespace c1 = NS1::NS2; cvise-2.3.0/clang_delta/tests/remove-namespace/namespace4.cpp000066400000000000000000000004541402162750500242040ustar00rootroot00000000000000namespace NS1 { template struct Base {}; template struct Derived: public Base { typename Derived::template Base* p1; }; } template struct Base {}; template struct Derived: public Base { typename Derived::template Base* p1; }; cvise-2.3.0/clang_delta/tests/remove-namespace/namespace4.output000066400000000000000000000005521402162750500247610ustar00rootroot00000000000000 template struct Trans_NS_NS1_Base {}; template struct Trans_NS_NS1_Derived: public Trans_NS_NS1_Base { typename Trans_NS_NS1_Derived::template Trans_NS_NS1_Base* p1; }; template struct Base {}; template struct Derived: public Base { typename Derived::template Trans_NS_NS1_Base* p1; }; cvise-2.3.0/clang_delta/tests/remove-namespace/namespace5.cpp000066400000000000000000000002201402162750500241740ustar00rootroot00000000000000namespace NS1 { } namespace NS2 { namespace NS1 { void foo() {} } namespace NS3 { using NS1::foo; void bar() { foo(); } } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace5.output000066400000000000000000000002001402162750500247500ustar00rootroot00000000000000 namespace NS2 { namespace NS1 { void foo() {} } namespace NS3 { using NS1::foo; void bar() { foo(); } } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace5.output2000066400000000000000000000002321402162750500250370ustar00rootroot00000000000000namespace NS1 { } namespace Trans_NS_NS2_NS1 { void foo() {} } namespace NS3 { using Trans_NS_NS2_NS1::foo; void bar() { foo(); } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace5.output3000066400000000000000000000001611402162750500250410ustar00rootroot00000000000000namespace NS1 { } namespace NS2 { void foo() {} namespace NS3 { void bar() { foo(); } } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace5.output4000066400000000000000000000002001402162750500250340ustar00rootroot00000000000000namespace NS1 { } namespace NS2 { namespace NS1 { void foo() {} } using NS1::foo; void bar() { foo(); } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace6.cpp000066400000000000000000000001471402162750500242050ustar00rootroot00000000000000namespace NS1 { void foo(); } namespace NS2 { using namespace NS1; void bar() { NS1::foo(); } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace6.output000066400000000000000000000000761402162750500247640ustar00rootroot00000000000000 void foo(); namespace NS2 { void bar() { foo(); } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace6.output2000066400000000000000000000001031402162750500250350ustar00rootroot00000000000000namespace NS1 { void foo(); } void bar() { NS1::foo(); } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace7.cpp000066400000000000000000000002251402162750500242030ustar00rootroot00000000000000namespace NS1 { namespace NS2 { void foo() {} } // NS2 } // NS1 namespace NS3 { using namespace NS1; void bar() { NS2::foo(); } } // NS3 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace7.output000066400000000000000000000001611402162750500247600ustar00rootroot00000000000000 namespace NS2 { void foo() {} } // NS2 // NS1 namespace NS3 { void bar() { NS2::foo(); } } // NS3 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace7.output2000066400000000000000000000002001402162750500250340ustar00rootroot00000000000000namespace NS1 { void foo() {} // NS2 } // NS1 namespace NS3 { using namespace NS1; void bar() { foo(); } } // NS3 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace7.output3000066400000000000000000000001661402162750500250500ustar00rootroot00000000000000namespace NS1 { namespace NS2 { void foo() {} } // NS2 } // NS1 void bar() { NS1::NS2::foo(); } // NS3 cvise-2.3.0/clang_delta/tests/remove-namespace/namespace8.cpp000066400000000000000000000002221402162750500242010ustar00rootroot00000000000000namespace NS1 { void foo(void) {} } // NS1 namespace NS2 { using NS1::foo; void bar() { foo();} } // NS2 void foo() {} void func() {foo();} cvise-2.3.0/clang_delta/tests/remove-namespace/namespace8.output000066400000000000000000000002151402162750500247610ustar00rootroot00000000000000 void Trans_NS_NS1_foo(void) {} // NS1 namespace NS2 { void bar() { Trans_NS_NS1_foo();} } // NS2 void foo() {} void func() {foo();} cvise-2.3.0/clang_delta/tests/remove-namespace/namespace8.output2000066400000000000000000000001701402162750500250430ustar00rootroot00000000000000namespace NS1 { void foo(void) {} } // NS1 void bar() { NS1::foo();} // NS2 void foo() {} void func() {foo();} cvise-2.3.0/clang_delta/tests/remove-namespace/namespace9.cpp000066400000000000000000000001061402162750500242030ustar00rootroot00000000000000void foo(); namespace NS2 { using ::foo; void bar () { foo(); } } cvise-2.3.0/clang_delta/tests/remove-namespace/namespace9.output000066400000000000000000000000521402162750500247610ustar00rootroot00000000000000void foo(); void bar () { foo(); } cvise-2.3.0/clang_delta/tests/remove-nested-function/000077500000000000000000000000001402162750500226265ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-nested-function/remove_nested_func1.cc000066400000000000000000000001631402162750500270700ustar00rootroot00000000000000struct S1 { S1(int); }; int foo(); int bar(int); struct f : S1 { f() : S1(bar(foo())) { bar(foo()); } }; cvise-2.3.0/clang_delta/tests/remove-nested-function/remove_nested_func1.output000066400000000000000000000002321402162750500300400ustar00rootroot00000000000000struct S1 { S1(int); }; int foo(); int bar(int); struct f : S1 { f() : S1(bar(foo())) { int __trans_tmp_1 = foo(); bar(__trans_tmp_1); } }; cvise-2.3.0/clang_delta/tests/remove-try-catch/000077500000000000000000000000001402162750500214175ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-try-catch/try-catch-1.cpp000066400000000000000000000006261402162750500241630ustar00rootroot00000000000000#include #include int main() { try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "Foo"; } catch(const std::exception &ex) { std::cerr << "Bar"; } try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "FooBar"; } return 0; } cvise-2.3.0/clang_delta/tests/remove-try-catch/try-catch-1.output000066400000000000000000000003221402162750500247320ustar00rootroot00000000000000#include #include int main() { try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "FooBar"; } return 0; } cvise-2.3.0/clang_delta/tests/remove-try-catch/try-catch-2.cpp000066400000000000000000000006261402162750500241640ustar00rootroot00000000000000#include #include int main() { try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "Foo"; } catch(const std::exception &ex) { std::cerr << "Bar"; } try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "FooBar"; } return 0; } cvise-2.3.0/clang_delta/tests/remove-try-catch/try-catch-2.output000066400000000000000000000005271402162750500247420ustar00rootroot00000000000000#include #include int main() { try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "Bar"; } try { int a = 6; std::cerr << "a = " << a << "\n"; } catch(const std::exception &ex) { std::cerr << "FooBar"; } return 0; } cvise-2.3.0/clang_delta/tests/remove-unused-enum-member/000077500000000000000000000000001402162750500232335ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-unused-enum-member/range.c000066400000000000000000000003551402162750500244760ustar00rootroot00000000000000enum processor_type { PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM, PROCESSOR_PENTIUMPRO, PROCESSOR_K6, PROCESSOR_ATHLON, PROCESSOR_PENTIUM4, PROCESSOR_max }; enum fpmath_unit { FPMATH_387 = 1, FPMATH_SSE = 2 }; cvise-2.3.0/clang_delta/tests/remove-unused-enum-member/range.output000066400000000000000000000002131402162750500256050ustar00rootroot00000000000000enum processor_type { PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM, }; enum fpmath_unit { FPMATH_SSE = 2 }; cvise-2.3.0/clang_delta/tests/remove-unused-field/000077500000000000000000000000001402162750500221055ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-unused-field/designated1.c000066400000000000000000000001101402162750500244310ustar00rootroot00000000000000struct { int x; int y; int z; } s = { .y = 2, 3, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated1.output000066400000000000000000000000701402162750500255540ustar00rootroot00000000000000struct { int y; int z; } s = { .y = 2, 3, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated2.c000066400000000000000000000001101402162750500244320ustar00rootroot00000000000000struct { int x; int y; int z; } s = { .y = 2, 3, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated2.output000066400000000000000000000000731402162750500255600ustar00rootroot00000000000000struct { int x; int z; } s = { 3, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated3.c000066400000000000000000000001031402162750500244350ustar00rootroot00000000000000struct { int x; int y; int z; } s = { .y = 2, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated3.output000066400000000000000000000000751402162750500255630ustar00rootroot00000000000000struct { int x; int y; } s = { .y = 2, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated4.c000066400000000000000000000001101402162750500244340ustar00rootroot00000000000000struct { int z; int x; int y; } s = { .y = 2, 3, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated4.output000066400000000000000000000000751402162750500255640ustar00rootroot00000000000000struct { int x; int y; } s = { .y = 2, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated5.c000066400000000000000000000001101402162750500244350ustar00rootroot00000000000000struct { int z; int x; int y; } s = { .y = 2, 3, .x = 1, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/designated5.output000066400000000000000000000000701402162750500255600ustar00rootroot00000000000000struct { int z; int y; } s = { .y = 2, 3, }; cvise-2.3.0/clang_delta/tests/remove-unused-field/unused_field1.c000066400000000000000000000001021402162750500247710ustar00rootroot00000000000000struct S { int f1; int f2; }; void foo() { S s = {1, 2}; } cvise-2.3.0/clang_delta/tests/remove-unused-field/unused_field1.output000066400000000000000000000000711402162750500261140ustar00rootroot00000000000000struct S { int f2; }; void foo() { S s = { 2}; } cvise-2.3.0/clang_delta/tests/remove-unused-field/unused_field2.c000066400000000000000000000001021402162750500247720ustar00rootroot00000000000000struct S { int f1; int f2; }; void foo() { S s = {1, 2}; } cvise-2.3.0/clang_delta/tests/remove-unused-field/unused_field2.output000066400000000000000000000000701402162750500261140ustar00rootroot00000000000000struct S { int f1; }; void foo() { S s = {1}; } cvise-2.3.0/clang_delta/tests/remove-unused-field/unused_field3.cpp000066400000000000000000000000641402162750500253420ustar00rootroot00000000000000void foo() { struct { int m; } a[] = {1}; } cvise-2.3.0/clang_delta/tests/remove-unused-field/unused_field3.output000066400000000000000000000000551402162750500261200ustar00rootroot00000000000000void foo() { struct { } a[] = {}; } cvise-2.3.0/clang_delta/tests/remove-unused-function/000077500000000000000000000000001402162750500226475ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-unused-function/class.cc000066400000000000000000000001021402162750500242540ustar00rootroot00000000000000class A { ~A() {} void foo(); }; void A::foo() { return; } cvise-2.3.0/clang_delta/tests/remove-unused-function/class.output000066400000000000000000000000731402162750500252360ustar00rootroot00000000000000class A { void foo(); }; void A::foo() { return; } cvise-2.3.0/clang_delta/tests/remove-unused-function/const.cc000066400000000000000000000001601402162750500243010ustar00rootroot00000000000000struct S { template void foo() const; template int operator+(int a) const; }; cvise-2.3.0/clang_delta/tests/remove-unused-function/const.output000066400000000000000000000001101402162750500252470ustar00rootroot00000000000000struct S { ; template int operator+(int a) const; }; cvise-2.3.0/clang_delta/tests/remove-unused-function/const.output2000066400000000000000000000000761402162750500253440ustar00rootroot00000000000000struct S { template void foo() const; ; }; cvise-2.3.0/clang_delta/tests/remove-unused-function/default.cc000066400000000000000000000001311402162750500245750ustar00rootroot00000000000000struct S1 { S1() = default; }; template struct S2 { S2() = default; }; cvise-2.3.0/clang_delta/tests/remove-unused-function/default.output000066400000000000000000000001121402162750500255470ustar00rootroot00000000000000struct S1 { }; template struct S2 { S2() = default; }; cvise-2.3.0/clang_delta/tests/remove-unused-function/default.output2000066400000000000000000000001121402162750500256310ustar00rootroot00000000000000struct S1 { S1() = default; }; template struct S2 { }; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete.cc000066400000000000000000000000741402162750500244210ustar00rootroot00000000000000struct S {}; template S foo(T &, T &) = delete; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete.output000066400000000000000000000000171402162750500253710ustar00rootroot00000000000000struct S {}; ; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete2.cc000066400000000000000000000003161402162750500245020ustar00rootroot00000000000000struct S1 { S1 foo() = delete; }; struct S2 { template S2 foo() = delete; }; template struct S3 { S3 foo() = delete; }; template struct S4 { S4 foo(); }; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete2.output000066400000000000000000000002741402162750500254600ustar00rootroot00000000000000struct S1 { }; struct S2 { template S2 foo() = delete; }; template struct S3 { S3 foo() = delete; }; template struct S4 { S4 foo(); }; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete2.output2000066400000000000000000000002451402162750500255400ustar00rootroot00000000000000struct S1 { S1 foo() = delete; }; struct S2 { ; }; template struct S3 { S3 foo() = delete; }; template struct S4 { S4 foo(); }; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete2.output3000066400000000000000000000002741402162750500255430ustar00rootroot00000000000000struct S1 { S1 foo() = delete; }; struct S2 { template S2 foo() = delete; }; template struct S3 { }; template struct S4 { S4 foo(); }; cvise-2.3.0/clang_delta/tests/remove-unused-function/delete2.output4000066400000000000000000000003051402162750500255370ustar00rootroot00000000000000struct S1 { S1 foo() = delete; }; struct S2 { template S2 foo() = delete; }; template struct S3 { S3 foo() = delete; }; template struct S4 { }; cvise-2.3.0/clang_delta/tests/remove-unused-function/inline_ns.cc000066400000000000000000000001601402162750500251310ustar00rootroot00000000000000namespace a { inline namespace b { using namespace a; } struct c; namespace { using a::c; } } cvise-2.3.0/clang_delta/tests/remove-unused-function/inline_ns.output000066400000000000000000000001601402162750500261040ustar00rootroot00000000000000namespace a { inline namespace b { using namespace a; } struct c; namespace { using a::c; } } cvise-2.3.0/clang_delta/tests/remove-unused-function/macro1.cc000066400000000000000000000000501402162750500243330ustar00rootroot00000000000000#define EXTERN extern EXTERN int foo(); cvise-2.3.0/clang_delta/tests/remove-unused-function/macro1.output000066400000000000000000000000271402162750500253120ustar00rootroot00000000000000#define EXTERN extern cvise-2.3.0/clang_delta/tests/remove-unused-function/macro2.cc000066400000000000000000000004261402162750500243430ustar00rootroot00000000000000#define __LEAF, __leaf__ #define __THROW __attribute__((__nothrow__ __LEAF)) # define __nonnull(params) __attribute__ ((__nonnull__ params)) extern void *foo(void* __restrict p1, const void* __restrict p2, int p3, unsigned p4) __THROW __nonnull ((1, 2)); cvise-2.3.0/clang_delta/tests/remove-unused-function/macro2.output000066400000000000000000000002171402162750500253140ustar00rootroot00000000000000#define __LEAF, __leaf__ #define __THROW __attribute__((__nothrow__ __LEAF)) # define __nonnull(params) __attribute__ ((__nonnull__ params)) cvise-2.3.0/clang_delta/tests/remove-unused-function/macro3.cc000066400000000000000000000004061402162750500243420ustar00rootroot00000000000000# define BEGIN_NAMESPACE_STD namespace std { # define END_NAMESPACE_STD } # define __THROW throw () # define __nonnull(params) BEGIN_NAMESPACE_STD extern void *foo(void *__restrict p1, unsigned p2) __THROW __nonnull ((1, 2)); END_NAMESPACE_STD cvise-2.3.0/clang_delta/tests/remove-unused-function/macro3.output000066400000000000000000000002471402162750500253200ustar00rootroot00000000000000# define BEGIN_NAMESPACE_STD namespace std { # define END_NAMESPACE_STD } # define __THROW throw () # define __nonnull(params) BEGIN_NAMESPACE_STD END_NAMESPACE_STD cvise-2.3.0/clang_delta/tests/remove-unused-function/template1.cc000066400000000000000000000001671402162750500250560ustar00rootroot00000000000000template void foo(T *); template struct S { template friend void foo(T1 *); }; cvise-2.3.0/clang_delta/tests/remove-unused-function/template1.output000066400000000000000000000001251402162750500260230ustar00rootroot00000000000000; template struct S { template friend void foo(T1 *); }; cvise-2.3.0/clang_delta/tests/remove-unused-function/template2.cc000066400000000000000000000002051402162750500250500ustar00rootroot00000000000000template struct S {template void foo();}; template template void S::foo() { } cvise-2.3.0/clang_delta/tests/remove-unused-function/template2.output000066400000000000000000000000451402162750500260250ustar00rootroot00000000000000template struct S {;}; cvise-2.3.0/clang_delta/tests/remove-unused-function/unused-funcs.cc000066400000000000000000000001561402162750500255770ustar00rootroot00000000000000void foo(); void bar(int x) { } extern int baz(int x, int y); extern "C" { long long f1() {} } cvise-2.3.0/clang_delta/tests/remove-unused-function/unused-funcs.output000066400000000000000000000001431402162750500265460ustar00rootroot00000000000000 void bar(int x) { } extern int baz(int x, int y); extern "C" { long long f1() {} } cvise-2.3.0/clang_delta/tests/remove-unused-var/000077500000000000000000000000001402162750500216125ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/remove-unused-var/struct1.c000066400000000000000000000000411402162750500233560ustar00rootroot00000000000000void foo() { struct S { } s; } cvise-2.3.0/clang_delta/tests/remove-unused-var/struct1.output000066400000000000000000000000401402162750500244730ustar00rootroot00000000000000void foo() { struct S { } ; } cvise-2.3.0/clang_delta/tests/remove-unused-var/struct2.c000066400000000000000000000000461402162750500233640ustar00rootroot00000000000000void foo() { struct S { } s1, s2; } cvise-2.3.0/clang_delta/tests/remove-unused-var/struct2.output000066400000000000000000000000431402162750500244770ustar00rootroot00000000000000void foo() { struct S { } s2; } cvise-2.3.0/clang_delta/tests/remove-unused-var/unused_var.cpp000066400000000000000000000000301402162750500244620ustar00rootroot00000000000000void foo() { int a; } cvise-2.3.0/clang_delta/tests/remove-unused-var/unused_var.output000066400000000000000000000000221402162750500252410ustar00rootroot00000000000000void foo() { } cvise-2.3.0/clang_delta/tests/rename-class/000077500000000000000000000000001402162750500206005ustar00rootroot00000000000000cvise-2.3.0/clang_delta/tests/rename-class/base_specifier.cpp000066400000000000000000000003431402162750500242470ustar00rootroot00000000000000namespace NS1 { template class Class1; template class Basic {}; template class Class1: public Basic {}; } namespace NS2 { class Class1; class Basic {}; class Class1: public Basic {}; } cvise-2.3.0/clang_delta/tests/rename-class/base_specifier.output000066400000000000000000000003331402162750500250240ustar00rootroot00000000000000namespace NS1 { template class Class1; template class A {}; template class Class1: public A {}; } namespace NS2 { class Class1; class Basic {}; class Class1: public Basic {}; } cvise-2.3.0/clang_delta/tests/rename-class/bool.cc000066400000000000000000000001361402162750500220420ustar00rootroot00000000000000namespace NS1 { template class AAA {}; } class BBB : public NS1::AAA {}; cvise-2.3.0/clang_delta/tests/rename-class/bool.output000066400000000000000000000001321402162750500230110ustar00rootroot00000000000000namespace NS1 { template class A {}; } class BBB : public NS1::A {}; cvise-2.3.0/clang_delta/tests/rename-class/class_template.cc000066400000000000000000000002721402162750500241100ustar00rootroot00000000000000template class SomeClass1 { public: SomeClass1() {} ~SomeClass1() {} }; template class SomeClass2 { public: SomeClass2() {} ~SomeClass2() {} }; cvise-2.3.0/clang_delta/tests/rename-class/class_template.output000066400000000000000000000002371402162750500250640ustar00rootroot00000000000000template class A { public: A() {} ~A() {} }; template class SomeClass2 { public: SomeClass2() {} ~SomeClass2() {} }; cvise-2.3.0/clang_delta/tests/rename-class/class_template2.cc000066400000000000000000000002651402162750500241740ustar00rootroot00000000000000template class SomeClass3 { public: SomeClass3() {} ~SomeClass3() {} }; template class SomeClass4 { public: SomeClass4() {} ~SomeClass4() {} }; cvise-2.3.0/clang_delta/tests/rename-class/class_template2.output000066400000000000000000000002321402162750500251410ustar00rootroot00000000000000template class A { public: A() {} ~A() {} }; template class SomeClass4 { public: SomeClass4() {} ~SomeClass4() {} }; cvise-2.3.0/clang_delta/tests/rename-class/dependent.cpp000066400000000000000000000002121402162750500232450ustar00rootroot00000000000000template struct Base {}; template struct Derived: public Base { typename Derived::template Base* p1; }; cvise-2.3.0/clang_delta/tests/rename-class/dependent.output000066400000000000000000000002011402162750500240210ustar00rootroot00000000000000template struct A {}; template struct Derived: public A { typename Derived::template A* p1; }; cvise-2.3.0/clang_delta/tests/rename-class/dependent_name.cpp000066400000000000000000000002211402162750500242450ustar00rootroot00000000000000template struct AAA { typedef T2 new_type; }; template struct BBB : public AAA::new_type { }; cvise-2.3.0/clang_delta/tests/rename-class/dependent_name.output000066400000000000000000000002151402162750500250260ustar00rootroot00000000000000template struct A { typedef T2 new_type; }; template struct BBB : public A::new_type { }; cvise-2.3.0/clang_delta/tests/rename-class/derive.cc000066400000000000000000000000611402162750500223620ustar00rootroot00000000000000class S1 {}; class S2:S1 { public: S2 () {} }; cvise-2.3.0/clang_delta/tests/rename-class/derive.output000066400000000000000000000000571402162750500233420ustar00rootroot00000000000000class A {}; class S2:A { public: S2 () {} }; cvise-2.3.0/clang_delta/tests/rename-class/dtor.cc000066400000000000000000000000611402162750500220540ustar00rootroot00000000000000class AAA { ~ AAA(); }; class HHH : AAA { }; cvise-2.3.0/clang_delta/tests/rename-class/dtor.output000066400000000000000000000000521402162750500230270ustar00rootroot00000000000000class A { ~A(); }; class HHH : A { }; cvise-2.3.0/clang_delta/tests/rename-class/dtor1.cc000066400000000000000000000001131402162750500221330ustar00rootroot00000000000000template class AAA { ~ AAA(); }; class HHH : AAA { }; cvise-2.3.0/clang_delta/tests/rename-class/dtor1.output000066400000000000000000000001041402162750500231060ustar00rootroot00000000000000template class A { ~A(); }; class HHH : A { }; cvise-2.3.0/clang_delta/tests/rename-class/elaborated_type1.cpp000066400000000000000000000002141402162750500245250ustar00rootroot00000000000000struct XXX {}; template struct AAA { typedef T2 new_type; }; struct BBB : public AAA::new_type { }; cvise-2.3.0/clang_delta/tests/rename-class/elaborated_type1.output000066400000000000000000000002101402162750500252770ustar00rootroot00000000000000struct A {}; template struct AAA { typedef T2 new_type; }; struct BBB : public AAA::new_type { }; cvise-2.3.0/clang_delta/tests/rename-class/elaborated_type2.cpp000066400000000000000000000001551402162750500245320ustar00rootroot00000000000000namespace NS { template class AAA {}; } template class BBB: NS::AAA {}; cvise-2.3.0/clang_delta/tests/rename-class/elaborated_type2.output000066400000000000000000000001511402162750500253040ustar00rootroot00000000000000namespace NS { template class A {}; } template class BBB: NS::A {}; cvise-2.3.0/clang_delta/tests/rename-class/explicit_specialization.cpp000066400000000000000000000001351402162750500262220ustar00rootroot00000000000000struct AAA {}; template class BBB {}; template<> class BBB : public AAA {}; cvise-2.3.0/clang_delta/tests/rename-class/explicit_specialization.output000066400000000000000000000001311402162750500267740ustar00rootroot00000000000000struct A {}; template class BBB {}; template<> class BBB : public A {}; cvise-2.3.0/clang_delta/tests/rename-class/forward_decl.cc000066400000000000000000000004371402162750500235460ustar00rootroot00000000000000namespace NS1 { template struct S1; template struct S2 {}; } namespace NS2 { template struct S1 : NS1::S1::type, T2> {}; } namespace NS1 { template struct S1 {}; } cvise-2.3.0/clang_delta/tests/rename-class/forward_decl.output000066400000000000000000000004341402162750500245160ustar00rootroot00000000000000namespace NS1 { template struct A; template struct S2 {}; } namespace NS2 { template struct S1 : NS1::A::type, T2> {}; } namespace NS1 { template struct A {}; } cvise-2.3.0/clang_delta/tests/rename-class/injected_name.cpp000066400000000000000000000001121402162750500240630ustar00rootroot00000000000000template struct AAA { AAA& foo(AAA *) { return *this; } }; cvise-2.3.0/clang_delta/tests/rename-class/injected_name.output000066400000000000000000000001041402162750500246420ustar00rootroot00000000000000template struct A { A& foo(A *) { return *this; } }; cvise-2.3.0/clang_delta/tests/rename-class/instantiation.cpp000066400000000000000000000001001402162750500241570ustar00rootroot00000000000000template struct AAA {}; template struct AAA; cvise-2.3.0/clang_delta/tests/rename-class/instantiation.output000066400000000000000000000000741402162750500247470ustar00rootroot00000000000000template struct A {}; template struct A; cvise-2.3.0/clang_delta/tests/rename-class/parm.cpp000066400000000000000000000002231402162750500222400ustar00rootroot00000000000000struct S1 {}; template class Base { int foo(S1) {} }; template class S2 : Base { int foo(S1) {} }; cvise-2.3.0/clang_delta/tests/rename-class/parm.output000066400000000000000000000002201402162750500230130ustar00rootroot00000000000000struct A {}; template class Base { int foo(A) {} }; template class S2 : Base { int foo(A) {} }; cvise-2.3.0/clang_delta/tests/rename-class/partial_specialization.cpp000066400000000000000000000002321402162750500260330ustar00rootroot00000000000000template struct S1 { T value() const { return N; } }; template struct S1 { T value() const { return 0; } }; cvise-2.3.0/clang_delta/tests/rename-class/partial_specialization.output000066400000000000000000000002301402162750500266070ustar00rootroot00000000000000template struct A { T value() const { return N; } }; template struct A { T value() const { return 0; } }; cvise-2.3.0/clang_delta/tests/rename-class/rename-class1.cpp000066400000000000000000000001511402162750500237340ustar00rootroot00000000000000class AAA { public: AAA() {} static int m1; }; int AAA::m1; void foo() { AAA a1; AAA::m1 = 1; } cvise-2.3.0/clang_delta/tests/rename-class/rename-class1.output000066400000000000000000000001371402162750500245160ustar00rootroot00000000000000class A { public: A() {} static int m1; }; int A::m1; void foo() { A a1; A::m1 = 1; } cvise-2.3.0/clang_delta/tests/rename-class/rename-class2.cpp000066400000000000000000000001461402162750500237410ustar00rootroot00000000000000struct ababababababababab { ~ababababababababab(); }; ababababababababab::~ababababababababab() {} cvise-2.3.0/clang_delta/tests/rename-class/rename-class2.output000066400000000000000000000000421402162750500245120ustar00rootroot00000000000000struct A { ~A(); }; A::~A() {} cvise-2.3.0/clang_delta/tests/rename-class/specialization.cpp000066400000000000000000000001051402162750500243160ustar00rootroot00000000000000template struct AAA {}; template<> struct AAA {}; cvise-2.3.0/clang_delta/tests/rename-class/specialization.output000066400000000000000000000001011402162750500250700ustar00rootroot00000000000000template struct A {}; template<> struct A {}; cvise-2.3.0/clang_delta/tests/rename-class/static_member.cc000066400000000000000000000001711402162750500237240ustar00rootroot00000000000000class AAA { public: AAA() {} static int m1; }; int AAA::m1; int foo(void) { AAA a1; AAA::m1 = 1; return 0; } cvise-2.3.0/clang_delta/tests/rename-class/static_member.output000066400000000000000000000001571402162750500247030ustar00rootroot00000000000000class A { public: A() {} static int m1; }; int A::m1; int foo(void) { A a1; A::m1 = 1; return 0; } cvise-2.3.0/clang_delta/tests/rename-class/template_class_1.cpp000066400000000000000000000000401402162750500245160ustar00rootroot00000000000000template class Base>; cvise-2.3.0/clang_delta/tests/rename-class/template_class_1.output000066400000000000000000000000351402162750500253000ustar00rootroot00000000000000template class A>; cvise-2.3.0/clang_delta/tests/rename-class/template_parm.cpp000066400000000000000000000000741402162750500241370ustar00rootroot00000000000000template class AAA { struct BBB : T1 {}; }; cvise-2.3.0/clang_delta/tests/rename-class/template_parm.output000066400000000000000000000000721402162750500247130ustar00rootroot00000000000000template class A { struct BBB : T1 {}; }; cvise-2.3.0/clang_delta/tests/rename-class/template_template.cpp000066400000000000000000000001601402162750500250070ustar00rootroot00000000000000template struct AAA {}; template