-
Notifications
You must be signed in to change notification settings - Fork 10
[CGFCOLLECTOR] Adding Fortran call graph collector #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gomfol12
wants to merge
143
commits into
tudasc:devel
Choose a base branch
from
gomfol12:fortran_collector
base: devel
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
143 commits
Select commit
Hold shift + click to select a range
b0e04d2
add/modified cmakefiles to add cgfcollector subproject
gomfol12 814f9f6
WIP: add simple function parsing and integrated graphlib
gomfol12 6975bcc
add wrapper and simple test script
gomfol12 87b0684
add main function mangling for fortran to correctly identify main fun…
gomfol12 8d643f3
add simple test case 1
gomfol12 037ab40
added test case using a module
gomfol12 a080385
fix typo in CMakeLists.txt and add precompiled headers
gomfol12 404c22d
rework main to construct CG and set hasBody property accordingly
gomfol12 bdbcebd
tests now ignore _MetaCG part in json file
gomfol12 8f1be87
update simple_01 test for MetaCG format version 3
gomfol12 64bc589
add some tests
gomfol12 7119e68
tests ignore the origin field as this differ from machines
gomfol12 2e822c5
nesting test for calls with %
gomfol12 ce27a50
function calls with % are now correctly parsed and generate dot files…
gomfol12 450775d
WIP: impl parsing for function overriding in derived types. And broke…
gomfol12 93be412
fix and cleanup the ProcedureDesignator parsing
gomfol12 678fc67
add -dot option to configure .dot generation
gomfol12 a4f8a57
more tests
gomfol12 6515153
WIP: impl finalizers parsing. Still overestimates
gomfol12 01d37ab
fix: problem with deferred keyword in abstract type where edges where…
gomfol12 8d1f3e2
simple 05 add output.json
gomfol12 8e3a298
impl operator overloading parsing, WIP: defined operator parsing
gomfol12 39d7247
better test case for operator overloading and defined operators
gomfol12 b8af6c8
better test case for finalizers
gomfol12 fe2c06f
tests: impl dedicated CG compare tool using node names to compare CGs…
gomfol12 94310d5
add cmake managed tests for multi file tests
gomfol12 6713d16
renamed test case 6 to operator
gomfol12 ffded8e
add basic README.md for cgfcollector
gomfol12 f9479d1
move some files in the tools directory
gomfol12 a96f443
more tests (function_test and math_demo)
gomfol12 8f7eb79
WIP: commit
gomfol12 3ad3851
WIP: normal operator parsing now working, operator in interfaces are …
gomfol12 361ad16
refactor: move ParseTreeVisitor into its own file
gomfol12 b7cfd40
fix operator and improved operator test
gomfol12 4b3f6f6
destructor now handeling the allocatable case with assignments
gomfol12 b3ab709
extended parsing and test for destructors for fix assignment(=), allo…
gomfol12 2fc0b03
renamed 03 test to final
gomfol12 5bac021
improved logging for debugging and fixes for destructor handling
gomfol12 811ef39
impl destructor handling for function arguments without allocatable attr
gomfol12 73840e2
test final simplified
gomfol12 80fce0f
test final2 for finalizers with function arguments without allocatabl…
gomfol12 81acb85
impl entry and add test case
gomfol12 7e4a7c2
renamed 01, 03 and 05 test cases to more descriptive names
gomfol12 12b98ff
add generic interface test
gomfol12 78bdd0c
removed cmake_base.txt
gomfol12 8f73fbb
simplified cmake tests
gomfol12 8e1189c
add output.json for multi_02 test
gomfol12 f78f839
renamed multi_02 test to multi_deps
gomfol12 9de5e89
add interop tests
gomfol12 1b1e7f0
destructor handling with static lifetimes and test
gomfol12 2af28d0
additional finalizer test
gomfol12 e0b1139
CMakeLists -g commend
gomfol12 db74d60
improved variable tracking, impl handling of allocatable trough funct…
gomfol12 8817e5b
more consistent function naming scheme
gomfol12 c309b9a
some fixes for destructor with allocatable vars and test
gomfol12 c9b4058
some code cleanup regarding operators
gomfol12 3a12a5b
add more operator tests
gomfol12 8b086ff
operator: improved interface operators and can now distinguish betwee…
gomfol12 32f0a27
remove typedef we are in c++
gomfol12 2d439a2
add cmake_base.txt to .gitignore
gomfol12 d98c443
comments
gomfol12 e024be2
improved CMakeLists.txt to make it more readable and now using differ…
gomfol12 e08743b
add test case with fortdepend to generate fortran module dependencies
gomfol12 9e5ea73
add fortran test file config for cmake and make to .gitignore
gomfol12 101128f
add script to act as normal compiler that also generates CG
gomfol12 45eb619
updated README.md
gomfol12 f544221
add partial test examples for function pointer and unlimited polymorp…
gomfol12 db5b06d
update to new metacg version
gomfol12 e74398b
fix test runner for fortdepend test
gomfol12 ed57966
update test metacg format version 3 -> 4
gomfol12 ca89d9a
swaped insert with getOrInsertNode to only insert nodes with unique n…
gomfol12 c9424a4
remove unnecessary includes
gomfol12 ac6eaa3
add FlangLLVM.cmake for correctly linking flang
gomfol12 a6b609a
fix comp_wrapper and add filtering for files in options
gomfol12 9cf0abd
flang_bin can now be set throw env var
gomfol12 85be0aa
don't link against flangFrontendTool
gomfol12 2f88d1c
main more consistant output filenames and new norename plugin for cma…
gomfol12 87f5b14
update tests to reflect main changes
gomfol12 b4aed45
add norename option to wrapper script
gomfol12 54f7399
compiler wrapper now correctly filters options and also extract optio…
gomfol12 b51b756
comp wrapper fix -o parsing
gomfol12 e7db8b4
fix for crash in expr's in specification part of module
gomfol12 005ff71
more consistent mangling, adjusted tests and fix typo
gomfol12 7cc1851
FlangLLVM.cmake added required clang package
gomfol12 462637f
fix cgManager wrong usage
gomfol12 c25a95d
test_runner.sh now count test cases run and failed
gomfol12 23fcdef
add empty tests
gomfol12 0e3dd5f
reenabled underscoring for mangling
gomfol12 4c08e21
cgfcollector_comp_wrapper ignore -fPIC for flang -fc1 call
gomfol12 4d7b92c
add missing _ to some function names
gomfol12 9505fe1
extract info from use definition for derived types and add some tests
gomfol12 f851502
forget to rename test files
gomfol12 086cbeb
fixed origin field in multi operator and use tests
gomfol12 80c6f63
add collection of interface operators from use statement. Same idea a…
gomfol12 c3f9a3d
add comment
gomfol12 2290fe2
fix test runner: some failed test got not counted as failed
gomfol12 d889e86
fix GenericDetails restrict to only IsIntrinsicOperator and fix typo
gomfol12 6a477d8
types array missing extendsfrom entry add more descriptive error msg
gomfol12 9b5e41e
fix: i am now collecting type though the inheritance structure correc…
gomfol12 ed5bd29
getFileEntry for llvm > 18
gomfol12 95a747b
moved compareSymbols, mangleSymbol to util file
gomfol12 5adc85f
refactor
gomfol12 dc8da8f
refactor
gomfol12 cb44c26
refactor
gomfol12 22fa7ba
add documentation
gomfol12 11f9d17
refactor and add documentation
gomfol12 f0b9521
use function struct for currentFunctions vector
gomfol12 bd3355b
doc and refector
gomfol12 5121eeb
refactor in individual files
gomfol12 a056e94
variableTracking doc
gomfol12 28cbb13
ParseTreeVisitor more doc
gomfol12 ec069d5
edgeManager refactor
gomfol12 32d818b
edgeManager refactor
gomfol12 e211136
rename type typeSymbol
gomfol12 88865f9
change to remove in handleTrackedVars
gomfol12 adc3a13
removed const_cast and resolved auto for clarity
gomfol12 47ec95b
add doc in tool scripts
gomfol12 396c7cb
updated cgfcollector README
gomfol12 08ce761
removed duplicate comment
gomfol12 0aba487
cmake uncomment/removed lines
gomfol12 7d05779
README: add context and fix typo
gomfol12 c2b5361
migration: CGCompare to CGDiff
gomfol12 da23036
removed CGCompare
gomfol12 c8d4114
simplify test script and integrate in cmake
gomfol12 11e693e
cmake add flangFrontendTool find
gomfol12 2b89059
Filename capitalization and license headers
gomfol12 00a6051
removed using namespace from header files and project-local includes …
gomfol12 5ec212a
use upper case type names
gomfol12 88c39ca
comment style
gomfol12 46d895b
Consistent naming for cgfcollector
gomfol12 d1ddaeb
add cgfcollector to ci pipeline
gomfol12 0571de7
namespacify
gomfol12 1ff47b0
more consistent whitespacing
gomfol12 46bacbb
removed FLANG_LITTLE_ENDIAN as it is platform specific and not required
gomfol12 17ed4c5
CMakeLists variable naming
gomfol12 4f762f9
better option parsing and verbose option
gomfol12 9026920
visuel -> visual and also added some option parsing
gomfol12 3ac9a60
removed visual tool
gomfol12 146504d
Updated README.md regarding options parsing and more consistent options
gomfol12 1be6138
clarified comment
gomfol12 ba2759b
simplified main
gomfol12 c93fd56
add doc to replaceExtension
gomfol12 872fd22
full-build container add missing mlir and flang deps
gomfol12 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| set(PROJECT_NAME cgfcollector) | ||
| set(TARGETS_EXPORT_NAME ${PROJECT_NAME}-target) | ||
|
|
||
| file( | ||
| GLOB | ||
| CGFCOLLECTOR_SOURCES | ||
| src/*.cpp | ||
| ) | ||
|
|
||
| add_library(${PROJECT_NAME} SHARED ${CGFCOLLECTOR_SOURCES}) | ||
| add_flang(${PROJECT_NAME}) | ||
| add_metacg(${PROJECT_NAME}) | ||
| add_spdlog_libraries(${PROJECT_NAME}) | ||
|
|
||
| target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) | ||
|
|
||
| install( | ||
| TARGETS ${PROJECT_NAME} | ||
| EXPORT ${TARGETS_EXPORT_NAME} | ||
| LIBRARY DESTINATION lib | ||
| ARCHIVE DESTINATION lib | ||
| ) | ||
|
|
||
| configure_package_config_file( | ||
| ${METACG_Directory}/cmake/Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake | ||
| INSTALL_DESTINATION lib/cmake | ||
| ) | ||
|
|
||
| install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake DESTINATION lib/cmake) | ||
|
|
||
| # generate wrapper scripts | ||
|
|
||
| function( | ||
| configure_file_and_install | ||
| TEMPLATE | ||
| OUTPUT_BASENAME | ||
| DESTINATION | ||
| ) | ||
| set(BUILD_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_BASENAME}") | ||
| set(INSTALL_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_BASENAME}.install") | ||
|
|
||
| # build-time values for development | ||
| set(CGFCOLLECTOR_FILE_NAME_LIB "${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.so") | ||
| set(CGFCOLLECTOR_CGDIFF_BIN "${CMAKE_BINARY_DIR}/tools/cgdiff/cgdiff") | ||
| set(CGFCOLLECTOR_WRAPPER "${CMAKE_CURRENT_BINARY_DIR}/cgfcollector_wrapper.sh") | ||
| set(CGFCOLLECTOR_TEST_CASES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/test") | ||
| set(CGMERGE2_BIN "${CMAKE_BINARY_DIR}/tools/cgmerge2/cgmerge2") | ||
|
|
||
| configure_file( | ||
| "${TEMPLATE}" | ||
| "${BUILD_OUTPUT}" | ||
| @ONLY | ||
| ) | ||
|
|
||
| if(DESTINATION | ||
| STREQUAL | ||
| "" | ||
| ) | ||
| return() | ||
| endif() | ||
|
|
||
| # install-time values | ||
| set(CGFCOLLECTOR_FILE_NAME_LIB "${CMAKE_INSTALL_PREFIX}/lib/lib${PROJECT_NAME}.so") | ||
|
|
||
| configure_file( | ||
| "${TEMPLATE}" | ||
| "${INSTALL_OUTPUT}" | ||
| @ONLY | ||
| ) | ||
|
|
||
| install( | ||
| PROGRAMS "${INSTALL_OUTPUT}" | ||
| DESTINATION "${DESTINATION}" | ||
| RENAME "${OUTPUT_BASENAME}" | ||
| ) | ||
| endfunction() | ||
|
|
||
| configure_file_and_install( | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/tools/cgfcollector_wrapper.sh.in" | ||
| "cgfcollector_wrapper.sh" | ||
| "bin" | ||
| ) | ||
|
|
||
| configure_file_and_install( | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/tools/cgfcollector_comp_wrapper.sh.in" | ||
| "cgfcollector_comp_wrapper.sh" | ||
| "bin" | ||
| ) | ||
|
|
||
| configure_file_and_install( | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/tools/test_runner.sh.in" | ||
| "test_runner.sh" | ||
| "" | ||
| ) | ||
|
|
||
| configure_file_and_install( | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/test/multi/cmake_base.txt.in" | ||
| "cmake_base.txt" | ||
| "" | ||
| ) | ||
| file( | ||
| RENAME | ||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake_base.txt" | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/test/multi/cmake_base.txt" | ||
| ) | ||
|
|
||
| configure_file_and_install( | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/test/multi/make_base.in" | ||
| "make_base" | ||
| "" | ||
| ) | ||
| file( | ||
gomfol12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| RENAME | ||
| "${CMAKE_CURRENT_BINARY_DIR}/make_base" | ||
| "${CMAKE_CURRENT_SOURCE_DIR}/test/multi/make_base" | ||
| ) | ||
|
|
||
| # tests | ||
| add_test(NAME cgfcollector_tests COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_runner.sh) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # CG Fortran collector | ||
|
|
||
| Fortran call graph generation tool for MetaCG. This tool is implemented as a | ||
| Flang plugin and generates a call graph from source-level. | ||
|
|
||
| ## Usage | ||
|
|
||
| For single file projects or projects not using modules use: | ||
|
|
||
| ```sh | ||
| cgfcollector_wrapper.sh [options] <source file/s> | ||
| ``` | ||
|
|
||
| For any other projects you need a build system. For this we provide another | ||
| script that acts as the normal Flang compiler but also produces a call graph. | ||
| [More info below](#generate-a-call-graph). | ||
|
|
||
| ```sh | ||
| cgfcollector_comp_wrapper.sh <source file/s> | ||
| ``` | ||
|
|
||
| You can also run the plugin directly with Flang: | ||
|
|
||
| ```sh | ||
| flang -fc1 -load "libcgfcollector.so" -plugin "genCG" [options] | ||
| ``` | ||
|
|
||
| Available options: | ||
|
|
||
| - `--dot`: Additionally generate a DOT file. This is mostly used for debugging. | ||
| - `--no-rename`: Do not rename the output file to `.json`. | ||
| - `--verbose`: Print additional information during the generation process. | ||
|
|
||
| Additionally these other tools are included: | ||
|
|
||
| - `cgfcollector_wrapper.sh`: Convenience wrapper to run parse plugin. | ||
| - `cgfcollector_comp_wrapper.sh`: Acts like a normal Flang compiler but also generates a call graph. | ||
| - `test_runner.sh`: Run tests. | ||
|
|
||
| ## How to build | ||
|
|
||
| To build the cgfcollector the option `METACG_BUILD_CGFCOLLECTOR` must be set to | ||
| `ON`. | ||
|
|
||
| ## Generate a call graph | ||
|
|
||
| ### from a CMake project | ||
|
|
||
| Paste this into your CMakeLists.txt. | ||
|
|
||
| ``` | ||
| set(CMAKE_Fortran_COMPILER <path to cgfcollector_wrapper.sh>) | ||
| set(CMAKE_Fortran_FLAGS "") | ||
| set(CMAKE_Fortran_COMPILE_OBJECT "<CMAKE_Fortran_COMPILER> --dot <DEFINES> <INCLUDES> <FLAGS> <SOURCE> -o <OBJECT>") | ||
| set(CMAKE_Fortran_LINK_EXECUTABLE "<path to cgmerge2> <TARGET> <OBJECTS>") | ||
| set(CMAKE_EXECUTABLE_SUFFIX .json) | ||
| ``` | ||
|
|
||
| This will hook into the CMake build process and generate a call graph instead of | ||
| an executable. | ||
|
|
||
| An example can be found in `test/multi/deps`. | ||
|
|
||
| ### from other projects | ||
|
|
||
| Use `cgfcollector_comp_wrapper.sh` or `cgfcollector_wrapper.sh` to hook into the | ||
| build process of your favorite tool and use the `cgmerge2` utility to merge the | ||
| partial generated call graphs. | ||
|
|
||
| An example can be found in `test/multi/fortdepend_deps`. This example uses | ||
| fortdepend to generate a module dependency list. If your build system already | ||
| generates such a list and executes the compiler on the files in the correct order | ||
| you probably don't need this. | ||
|
|
||
| ## Running test | ||
|
|
||
| Run `test_runner.sh` | ||
|
|
||
| NOTE: The test `test/multi/fortdepend_deps` has a dependency on [fortdepend](https://fortdepend.readthedocs.io/en/latest/) | ||
|
|
||
| ## Debugging | ||
|
|
||
| ### print parse tree | ||
|
|
||
| ```sh | ||
| flang-new -fc1 -fdebug-dump-parse-tree file.f90 | ||
| ``` |
gomfol12 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /** | ||
| * File: Edge.h | ||
| * License: Part of the MetaCG project. Licensed under BSD 3 clause license. See LICENSE.txt file at | ||
| * https://github.com/tudasc/metacg/LICENSE.txt | ||
| */ | ||
|
|
||
| #pragma once | ||
gomfol12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #include "FortranUtil.h" | ||
| #include "Type.h" | ||
|
|
||
| #include <LoggerUtil.h> | ||
| #include <flang/Parser/parse-tree.h> | ||
| #include <flang/Semantics/symbol.h> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| namespace metacg::cgfcollector { | ||
|
|
||
| struct PotentialFinalizer; | ||
|
|
||
| struct Edge { | ||
| std::string caller; | ||
| std::string callee; | ||
|
|
||
| Edge(std::string caller, std::string callee) : caller(std::move(caller)), callee(std::move(callee)) {} | ||
|
|
||
| bool operator==(const Edge& other) const { return caller == other.caller && callee == other.callee; } | ||
| bool operator<(const Edge& other) const { | ||
| return caller < other.caller || (caller == other.caller && callee < other.callee); | ||
| } | ||
| }; // namespace metacg::cgfcollector | ||
|
|
||
| struct EdgeSymbol { | ||
| const Fortran::semantics::Symbol* caller; | ||
| const Fortran::semantics::Symbol* callee; | ||
|
|
||
| EdgeSymbol(const Fortran::semantics::Symbol* caller, const Fortran::semantics::Symbol* callee) | ||
| : caller(caller), callee(callee) {} | ||
|
|
||
| bool operator==(const EdgeSymbol& other) const { return caller == other.caller && callee == other.callee; } | ||
| bool operator<(const EdgeSymbol& other) const { | ||
| return caller < other.caller || (caller == other.caller && callee < other.callee); | ||
| } | ||
| }; | ||
|
|
||
| struct EdgeManager { | ||
| std::vector<Edge>& edges; | ||
|
|
||
| EdgeManager(std::vector<Edge>& edges) : edges(edges) {} | ||
|
|
||
| void addEdge(const EdgeSymbol& e); | ||
| void addEdge(const Fortran::semantics::Symbol* caller, const Fortran::semantics::Symbol* callee); | ||
| void addEdge(const Edge& e); | ||
| void addEdge(const std::string& caller, const std::string& callee); | ||
| void addEdges(const std::vector<Edge>& newEdges); | ||
| void addEdges(const std::vector<EdgeSymbol>& newEdges); | ||
|
|
||
| /** | ||
| * @brief For a given symbol, returns a list of edges from the current function to all finalizers of that type. | ||
| * | ||
| * @param types | ||
| * @param currentFunctionSymbol | ||
| * @param symbol | ||
| */ | ||
| [[nodiscard]] std::vector<EdgeSymbol> getEdgesForFinalizers(const std::vector<Type>& types, | ||
| const Fortran::semantics::Symbol* currentFunctionSymbol, | ||
| const Fortran::semantics::Symbol* symbol); | ||
| /** | ||
| * @brief Calls getEdgesForFinalizers and adds them to the edges vector. | ||
| * | ||
| * @param types | ||
| * @param currentFunctionSymbol | ||
| * @param symbol | ||
| */ | ||
| void addEdgesForFinalizers(const std::vector<Type>& types, const Fortran::semantics::Symbol* currentFunctionSymbol, | ||
| const Fortran::semantics::Symbol* symbol); | ||
|
|
||
| void addEdgesForFinalizers(const PotentialFinalizer& e); | ||
| }; | ||
|
|
||
| } // namespace metacg::cgfcollector | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.