├── .circleci └── config.yml ├── .gitmodules ├── CMake ├── config.cmake ├── install.cmake └── srcslice.cmake ├── CMakeLists.txt ├── README.md ├── src ├── CMakeLists.txt ├── cpp │ └── srcslice.cpp └── headers │ ├── InitPolicy.hpp │ └── srcslicepolicy.hpp └── test ├── CMakeLists.txt └── srcslicetest.cpp /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: cnewman/swum_srcml_integration_v2:latest 6 | steps: 7 | - checkout 8 | - run: git clone --recursive https://github.com/cnewman/srcSlice.git 9 | - run: cd srcSlice 10 | - run: git submodule update --init --remote --recursive 11 | - run: mkdir build 12 | - run: cd build && cmake .. 13 | - run: cd build && make -j3 14 | - run: cd build && ./bin/testsrcslice -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "srcSAX"] 2 | path = srcSAX 3 | url = https://github.com/srcML/srcSAX.git 4 | [submodule "srcSAXEventDispatch"] 5 | path = srcSAXEventDispatch 6 | url = https://github.com/srcML/srcSAXEventDispatch.git 7 | branch = master -------------------------------------------------------------------------------- /CMake/config.cmake: -------------------------------------------------------------------------------- 1 | ## 2 | # config.cmake 3 | # 4 | # Copyright (C) 2014-2015 SDML (www.sdml.info) 5 | # 6 | # This file is part of the srcSlice. 7 | # 8 | # The srcSlice is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # The srcSlice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with the srcSlice; if not, write to the Free Software 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | # 22 | # Build configuration file 23 | 24 | # build options 25 | #option(BUILD_UNIT_TESTS "Build unit tests for srcSlice" ON) 26 | #option(BUILD_EXAMPLES "Build example tests for srcSlice" ON) 27 | 28 | # find needed libraries 29 | find_package(LibXml2 REQUIRED) 30 | 31 | # include needed includes 32 | include_directories(${LIBXML2_INCLUDE_DIR}) 33 | add_definitions("-std=c++0x -O3") 34 | 35 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 36 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 37 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 38 | -------------------------------------------------------------------------------- /CMake/install.cmake: -------------------------------------------------------------------------------- 1 | ## 2 | # install.cmake 3 | # 4 | # Copyright (C) 2014-2015 SDML (www.sdml.info) 5 | # 6 | # This file is part of the srcSlice. 7 | # 8 | # The srcSlice is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # The srcSlice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with the srcSlice; if not, write to the Free Software 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | 22 | if(NOT WIN32) 23 | set(CMAKE_INSTALL_PREFIX "/usr/local") 24 | endif() 25 | -------------------------------------------------------------------------------- /CMake/srcslice.cmake: -------------------------------------------------------------------------------- 1 | ## 2 | # srcslice.cmake 3 | # 4 | # Copyright (C) 2014 SDML (www.sdml.info) 5 | # 6 | # This file is part of the srcSlice. 7 | # 8 | # The srcSlice is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # The srcSlice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with the srcSlice; if not, write to the Free Software 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | 22 | include(config) 23 | include(install) 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ## 2 | # CMakeLists.txt 3 | # 4 | # Copyright (C) 2015 SDML (www.sdml.info) 5 | # 6 | # This file is part of the srcSlice. 7 | # 8 | # The srcSlice is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # The srcSlice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with the srcSlice; if not, write to the Free Software 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | # 22 | # Build configuration file 23 | 24 | cmake_minimum_required(VERSION 2.8) 25 | project(srcSlice) 26 | 27 | # find needed libraries 28 | find_package(LibXml2 REQUIRED) 29 | find_package(GTest REQUIRED) 30 | 31 | set(CMAKE_CXX_STANDARD 14) 32 | set(CMAKE_CXX_FLAGS "-O0 -Wno-reorder -Wunused-variable -Wunused-parameter") 33 | 34 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 35 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 36 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 37 | 38 | include_directories(${LIBXML2_INCLUDE_DIR} 39 | ${CMAKE_SOURCE_DIR}/srcSAXEventDispatch/srcSAX/src/srcsax 40 | ${CMAKE_SOURCE_DIR}/srcSAXEventDispatch/srcSAX/src/cpp 41 | ${CMAKE_SOURCE_DIR}/srcSAXEventDispatch/srcSAX/src/windows 42 | srcSAXEventDispatch/src/dispatcher 43 | srcSAXEventDispatch/src/policy_classes 44 | src/headers) 45 | add_subdirectory(src) 46 | add_subdirectory(test) 47 | add_subdirectory(srcSAXEventDispatch) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # srcSlice 2 | Lightweight tool for slicing 3 | 4 | NOTE: Current version of srcSlice in the master branch is a new version that will take advantage of the event dispatcher framework. It is under construction, but it should work. Give it a try! 5 | 6 | If you'd like the old version of srcSlice, switch to the "old" srcslice branch. This is the version we presented at ICSE 16. 7 | 8 | To build srcSlice: 9 | 10 | 1. Clone the repository with 'git clone --recursive' into the desired directory. Make sure you include the --recursive as srcSlice includes a submodule that must also be cloned. 11 | 12 | 2. Outside of the cloned directory, create a new directory for the build. (This guide assumes the new directory is at the same directory tree level as the cloned directory) 13 | 14 | 3. Enter the new directory (not the cloned one) and type 'cmake ../{cloned directory}' 15 | 16 | 4. After cmake runs, simply type 'make' and all files should be built. 17 | 18 | 5. Once everything is built, go into the 'bin' folder and that's where the executable will be. 19 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB DISPATCHER_SOURCE dispatcher/*.cpp) 2 | file(GLOB DISPATCHER_HEADER dispatcher/*.hpp) 3 | 4 | file(GLOB SLICE_SOURCE cpp/*.cpp) 5 | file(GLOB SLICE_HEADER headers/*.hpp) 6 | 7 | add_executable(srcslice ${DISPATCHER_SOURCE} ${DISPATCHER_HEADER} ${SLICE_SOURCE} ${SLICE_HEADER}) 8 | target_link_libraries(srcslice srcsaxeventdispatch srcsax_static ${LIBXML2_LIBRARIES}) -------------------------------------------------------------------------------- /src/cpp/srcslice.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char** argv){ 3 | if(argc < 2){ 4 | std::cerr<<"Syntax: ./srcslice [srcML file name]"<> profileMap; 8 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 9 | srcSAXController control(argv[1]); 10 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 11 | control.parse(&handler); //Start parsing 12 | for(auto it : profileMap){ 13 | for(auto profile : it.second){ 14 | if(profile.containsDeclaration) 15 | profile.PrintProfile(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/headers/InitPolicy.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file InitPolicy.hpp 3 | * 4 | * @copyright Copyright (C) 2013-2014 SDML (www.srcML.org) 5 | * 6 | * The srcML Toolkit is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * The srcML Toolkit is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the srcML Toolkit; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #ifndef INITPOLICY 26 | #define INITPOLICY 27 | class InitPolicy : public srcSAXEventDispatch::EventListener, public srcSAXEventDispatch::PolicyDispatcher, public srcSAXEventDispatch::PolicyListener { 28 | public: 29 | struct InitData{ 30 | InitData() {} 31 | void clear(){ 32 | uses.clear(); 33 | } 34 | std::string nameOfIdentifier; 35 | std::set uses; //could be used multiple times in same init 36 | }; 37 | struct InitDataSet{ 38 | InitDataSet() = default; 39 | InitDataSet(std::map dat){ 40 | dataSet = dat; 41 | } 42 | void clear(){ 43 | dataSet.clear(); 44 | } 45 | std::map dataSet; 46 | }; 47 | std::map dataSet; 48 | ~InitPolicy(){} 49 | InitPolicy(std::initializer_list listeners = {}): srcSAXEventDispatch::PolicyDispatcher(listeners){ 50 | seenAssignment = false; 51 | InitializeEventHandlers(); 52 | } 53 | void Notify(const PolicyDispatcher * policy, const srcSAXEventDispatch::srcSAXEventContext & ctx) override {} //doesn't use other parsers 54 | void NotifyWrite(const PolicyDispatcher * policy, srcSAXEventDispatch::srcSAXEventContext & ctx) override {} //doesn't use other parsers 55 | protected: 56 | void * DataInner() const override { 57 | return new InitDataSet(dataSet); 58 | } 59 | private: 60 | InitData data; 61 | std::string currentTypeName, currentInitName, currentModifier, currentSpecifier; 62 | std::vector currentLine; 63 | bool seenAssignment; 64 | void InitializeEventHandlers(){ 65 | using namespace srcSAXEventDispatch; 66 | closeEventMap[ParserState::modifier] = [this](srcSAXEventContext& ctx){ 67 | 68 | }; 69 | 70 | closeEventMap[ParserState::name] = [this](srcSAXEventContext& ctx){ 71 | if(currentLine.empty() || currentLine.back() != ctx.currentLineNumber){ 72 | currentLine.push_back(ctx.currentLineNumber); 73 | } 74 | if(ctx.IsOpen({ParserState::declstmt})){ 75 | auto it = dataSet.find(currentInitName); 76 | if(it != dataSet.end()){ 77 | it->second.uses.insert(currentLine.back()); //assume it's a use 78 | }else{ 79 | data.nameOfIdentifier = currentInitName; 80 | data.uses.insert(currentLine.back()); 81 | dataSet.insert(std::make_pair(currentInitName, data)); 82 | } 83 | } 84 | }; 85 | 86 | closeEventMap[ParserState::tokenstring] = [this](srcSAXEventContext& ctx){ 87 | //TODO: possibly, this if-statement is suppressing more than just unmarked whitespace. Investigate. 88 | if(!(ctx.currentToken.empty() || ctx.currentToken == " ")){ 89 | if(ctx.And({ParserState::name, ParserState::init, ParserState::declstmt}) && ctx.Nor({ParserState::specifier, ParserState::modifier, ParserState::op})){ 90 | currentInitName = ctx.currentToken; 91 | } 92 | if(ctx.And({ParserState::specifier, ParserState::init, ParserState::declstmt})){ 93 | currentSpecifier = ctx.currentToken; 94 | } 95 | if(ctx.And({ParserState::modifier, ParserState::declstmt})){ 96 | currentModifier = ctx.currentToken; 97 | } 98 | } 99 | }; 100 | closeEventMap[ParserState::init] = [this](srcSAXEventContext& ctx){ 101 | NotifyAll(ctx); 102 | currentLine.pop_back(); 103 | seenAssignment = false; 104 | currentLine.clear(); 105 | dataSet.clear(); 106 | data.clear(); 107 | }; 108 | 109 | } 110 | }; 111 | #endif -------------------------------------------------------------------------------- /src/headers/srcslicepolicy.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SRCSLICEPOLICY 2 | #define SRCSLICEPOLICY 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | bool StringContainsCharacters(const std::string &str) { 17 | for (char ch : str) { 18 | if (std::isalpha(ch)) { 19 | return true; 20 | } 21 | } 22 | return false; 23 | } 24 | 25 | class SliceProfile { 26 | public: 27 | SliceProfile() : index(0), containsDeclaration(false), potentialAlias(false), dereferenced(false), 28 | isGlobal(false) {} 29 | 30 | SliceProfile( 31 | std::string name, int line, bool alias = 0, bool global = 0, 32 | std::set aDef = {}, std::set aUse = {}, 33 | std::vector> cFunc = {}, 34 | std::set dv = {}, bool containsDecl = false, 35 | std::set> edges = {}, bool visit = false) : 36 | variableName(name), lineNumber(line), potentialAlias(alias), 37 | isGlobal(global), definitions(aDef), uses(aUse), cfunctions(cFunc), 38 | dvars(dv), containsDeclaration(containsDecl), controlEdges(edges), 39 | visited(visit) { 40 | 41 | dereferenced = false; 42 | } 43 | 44 | void PrintProfile() { 45 | std::cout << "==========================================================================" << std::endl; 46 | std::cout << "Name and type: " << variableName << " " << variableType << std::endl; 47 | std::cout << "Contains Declaration: " << containsDeclaration << " " << "Containing class: " 48 | << nameOfContainingClass << std::endl; 49 | std::cout << "Dvars: {"; 50 | for (auto dvar : dvars) { 51 | std::cout << dvar << ","; 52 | } 53 | std::cout << "}" << std::endl; 54 | std::cout << "Aliases: {"; 55 | for (auto alias : aliases) { 56 | std::cout << alias << ","; 57 | } 58 | std::cout << "}" << std::endl; 59 | std::cout << "Cfunctions: {"; 60 | for (auto cfunc : cfunctions) { 61 | std::cout << cfunc.first << " " << cfunc.second << ","; 62 | } 63 | std::cout << "}" << std::endl; 64 | std::cout << "Use: {"; 65 | for (auto use : uses) { 66 | std::cout << use << ","; 67 | } 68 | std::cout << "}" << std::endl; 69 | std::cout << "Def: {"; 70 | for (auto def : definitions) { 71 | std::cout << def << ","; 72 | } 73 | std::cout << "}" << std::endl; 74 | std::cout << "Control Edges: {"; 75 | for (auto edge : controlEdges) { 76 | std::cout << "(" << edge.first << ", " << edge.second << ")" << ","; 77 | } 78 | std::cout << "}" << std::endl; 79 | std::cout << "==========================================================================" << std::endl; 80 | } 81 | 82 | unsigned int index; 83 | int lineNumber; 84 | std::string file; 85 | std::string function; 86 | std::string nameOfContainingClass; 87 | bool potentialAlias; 88 | bool dereferenced; 89 | 90 | bool isGlobal; 91 | bool containsDeclaration; 92 | 93 | std::string variableName; 94 | std::string variableType; 95 | std::unordered_set memberVariables; 96 | 97 | std::set definitions; 98 | std::set uses; 99 | 100 | std::set dvars; 101 | std::set aliases; 102 | 103 | std::vector> cfunctions; 104 | 105 | std::set> controlEdges; 106 | 107 | bool visited; 108 | }; 109 | 110 | class SrcSlicePolicy 111 | : public srcSAXEventDispatch::EventListener, 112 | public srcSAXEventDispatch::PolicyDispatcher, 113 | public srcSAXEventDispatch::PolicyListener { 114 | public: 115 | ~SrcSlicePolicy() {}; 116 | std::unordered_map> *profileMap; 117 | 118 | SrcSlicePolicy(std::unordered_map> *pm, 119 | std::initializer_list listeners = {}) 120 | : srcSAXEventDispatch::PolicyDispatcher(listeners) { 121 | // making SSP a listener for FSPP 122 | InitializeEventHandlers(); 123 | 124 | declPolicy.AddListener(this); 125 | exprPolicy.AddListener(this); 126 | callPolicy.AddListener(this); 127 | initPolicy.AddListener(this); 128 | paramPolicy.AddListener(this); 129 | functionPolicy.AddListener(this); 130 | 131 | profileMap = pm; 132 | } 133 | 134 | void Notify(const PolicyDispatcher *policy, const srcSAXEventDispatch::srcSAXEventContext &ctx) override { 135 | using namespace srcSAXEventDispatch; 136 | if (typeid(DeclTypePolicy) == typeid(*policy)) { 137 | decldata = *policy->Data(); 138 | auto sliceProfileItr = profileMap->find(decldata.nameOfIdentifier); 139 | 140 | //Just add new slice profile if name already exists. Otherwise, add new entry in map. 141 | if (sliceProfileItr != profileMap->end()) { 142 | auto sliceProfile = SliceProfile(decldata.nameOfIdentifier, decldata.lineNumber, 143 | (decldata.isPointer || decldata.isReference), true, 144 | std::set{decldata.lineNumber}); 145 | sliceProfile.nameOfContainingClass = ctx.currentClassName; 146 | sliceProfileItr->second.push_back(sliceProfile); 147 | sliceProfileItr->second.back().containsDeclaration = true; 148 | } else { 149 | auto sliceProf = SliceProfile(decldata.nameOfIdentifier, decldata.lineNumber, 150 | (decldata.isPointer || decldata.isReference), false, 151 | std::set{decldata.lineNumber}); 152 | sliceProf.nameOfContainingClass = ctx.currentClassName; 153 | sliceProf.containsDeclaration = true; 154 | profileMap->insert(std::make_pair(decldata.nameOfIdentifier, 155 | std::vector{ 156 | std::move(sliceProf) 157 | })); 158 | } 159 | sliceProfileItr = profileMap->find(decldata.nameOfIdentifier); 160 | //look at the dvars and add this current variable to their dvar's lists. If we haven't seen this name before, add its slice profile 161 | for (std::string dvar : declDvars) { 162 | auto updateDvarAtThisLocation = profileMap->find(dvar); 163 | if (updateDvarAtThisLocation != profileMap->end()) { 164 | if (!StringContainsCharacters(decldata.nameOfIdentifier)) continue; 165 | if (sliceProfileItr != profileMap->end() && sliceProfileItr->second.back().potentialAlias) { 166 | updateDvarAtThisLocation->second.back().aliases.insert(decldata.nameOfIdentifier); 167 | continue; 168 | } 169 | updateDvarAtThisLocation->second.back().dvars.insert(decldata.nameOfIdentifier); 170 | } else { 171 | auto sliceProf = SliceProfile(dvar, decldata.lineNumber, false, false, std::set{}, 172 | std::set{decldata.lineNumber}); 173 | sliceProf.nameOfContainingClass = ctx.currentClassName; 174 | auto newSliceProfileFromDeclDvars = profileMap->insert(std::make_pair(dvar, 175 | std::vector{ 176 | std::move(sliceProf) 177 | })); 178 | if (!StringContainsCharacters(decldata.nameOfIdentifier)) continue; 179 | if (sliceProfileItr != profileMap->end() && sliceProfileItr->second.back().potentialAlias) { 180 | newSliceProfileFromDeclDvars.first->second.back().aliases.insert(decldata.nameOfIdentifier); 181 | continue; 182 | } 183 | newSliceProfileFromDeclDvars.first->second.back().dvars.insert(decldata.nameOfIdentifier); 184 | } 185 | } 186 | declDvars.clear(); 187 | decldata.clear(); 188 | } else if (typeid(ExprPolicy) == typeid(*policy)) { 189 | exprDataSet = *policy->Data(); 190 | //iterate through every token found in the expression statement 191 | for (auto exprdata : exprDataSet.dataSet) { 192 | auto sliceProfileExprItr = profileMap->find(exprdata.second.nameOfIdentifier); 193 | auto sliceProfileLHSItr = profileMap->find(exprDataSet.lhsName); 194 | //Just update definitions and uses if name already exists. Otherwise, add new name. 195 | if (sliceProfileExprItr != profileMap->end()) { 196 | sliceProfileExprItr->second.back().nameOfContainingClass = ctx.currentClassName; 197 | sliceProfileExprItr->second.back().uses.insert(exprdata.second.uses.begin(), 198 | exprdata.second.uses.end()); 199 | sliceProfileExprItr->second.back().definitions.insert(exprdata.second.definitions.begin(), 200 | exprdata.second.definitions.end()); 201 | 202 | if (!StringContainsCharacters(exprDataSet.lhsName)) continue; 203 | if (sliceProfileLHSItr != profileMap->end() && sliceProfileLHSItr->second.back().potentialAlias) { 204 | sliceProfileExprItr->second.back().aliases.insert(exprDataSet.lhsName); 205 | continue; 206 | } 207 | if (!StringContainsCharacters(currentName)) continue; 208 | if (!currentName.empty() && 209 | (exprdata.second.lhs || currentName != exprdata.second.nameOfIdentifier)) { 210 | sliceProfileExprItr->second.back().dvars.insert(currentName); 211 | continue; 212 | } 213 | 214 | } else { 215 | auto sliceProfileExprItr2 = profileMap->insert(std::make_pair(exprdata.second.nameOfIdentifier, 216 | std::vector{ 217 | SliceProfile( 218 | exprdata.second.nameOfIdentifier, 219 | ctx.currentLineNumber, 220 | false, false, 221 | exprdata.second.definitions, 222 | exprdata.second.uses) 223 | })); 224 | sliceProfileExprItr2.first->second.back().nameOfContainingClass = ctx.currentClassName; 225 | 226 | if (!StringContainsCharacters(exprDataSet.lhsName)) continue; 227 | if (sliceProfileLHSItr != profileMap->end() && sliceProfileLHSItr->second.back().potentialAlias) { 228 | sliceProfileExprItr2.first->second.back().aliases.insert(exprDataSet.lhsName); 229 | continue; 230 | } 231 | //Only ever record a variable as being a dvar of itself if it was seen on both sides of = 232 | if (!StringContainsCharacters(currentName)) continue; 233 | if (!currentName.empty() && 234 | (exprdata.second.lhs || currentName != exprdata.second.nameOfIdentifier)) { 235 | sliceProfileExprItr2.first->second.back().dvars.insert(currentName); 236 | continue; 237 | } 238 | } 239 | } 240 | exprDataSet.clear(); 241 | } else if (typeid(InitPolicy) == typeid(*policy)) { 242 | initDataSet = *policy->Data(); 243 | //iterate through every token found in the initialization of a decl_stmt 244 | for (auto initdata : initDataSet.dataSet) { 245 | declDvars.push_back(initdata.second.nameOfIdentifier); 246 | auto sliceProfileItr = profileMap->find(initdata.second.nameOfIdentifier); 247 | //Just update definitions and uses if name already exists. Otherwise, add new name. 248 | if (sliceProfileItr != profileMap->end()) { 249 | sliceProfileItr->second.back().uses.insert(initdata.second.uses.begin(), 250 | initdata.second.uses.end()); 251 | } else { 252 | auto sliceProf = SliceProfile(initdata.second.nameOfIdentifier, ctx.currentLineNumber, false, false, 253 | std::set{}, initdata.second.uses); 254 | sliceProf.nameOfContainingClass = ctx.currentClassName; 255 | profileMap->insert(std::make_pair(initdata.second.nameOfIdentifier, 256 | std::vector{sliceProf})); 257 | } 258 | } 259 | initDataSet.clear(); 260 | } else if (typeid(CallPolicy) == typeid(*policy)) { 261 | calldata = *policy->Data(); 262 | bool isFuncNameNext = false; 263 | std::vector> funcNameAndCurrArgumentPos; 264 | //Go through each token found in a function call 265 | for (auto currentCallToken : calldata.callargumentlist) { 266 | //Check to see if we are entering a function call or exiting-- 267 | //if entering, we know the next token is the name of the call 268 | //otherwise, we're exiting and need to pop the current function call off the stack 269 | switch (currentCallToken[0]) { 270 | case '(': { 271 | isFuncNameNext = true; 272 | continue; 273 | } 274 | case ')': { 275 | if (!funcNameAndCurrArgumentPos.empty()) funcNameAndCurrArgumentPos.pop_back(); 276 | continue; 277 | } 278 | } 279 | //If we noted that a function name was coming in that switch above, record it here. 280 | //Otherwise, the next token is an argument in the function call 281 | if (isFuncNameNext) { 282 | funcNameAndCurrArgumentPos.push_back(std::make_pair(currentCallToken, 1)); 283 | isFuncNameNext = false; 284 | } else { 285 | auto sliceProfileItr = profileMap->find(currentCallToken); 286 | 287 | std::string callOrder, argumentOrder; 288 | for (auto name : funcNameAndCurrArgumentPos) { 289 | if (!StringContainsCharacters(name.first)) continue; 290 | callOrder += name.first + '-'; 291 | argumentOrder += std::to_string(name.second) + '-'; 292 | } 293 | if (!callOrder.empty())callOrder.erase(callOrder.size() - 1); ///need to implement join 294 | if (!argumentOrder.empty()) argumentOrder.erase(argumentOrder.size() - 1); ///need to implement join 295 | 296 | //Just update cfunctions if name already exists. Otherwise, add new name. 297 | if (sliceProfileItr != profileMap->end()) { 298 | sliceProfileItr->second.back().cfunctions.push_back(std::make_pair(callOrder, argumentOrder)); 299 | } else { 300 | auto sliceProf = SliceProfile(currentCallToken, ctx.currentLineNumber, true, true, 301 | std::set{}, 302 | std::set{ctx.currentLineNumber}, 303 | std::vector>{ 304 | std::make_pair(callOrder, argumentOrder)}); 305 | sliceProf.nameOfContainingClass = ctx.currentClassName; 306 | profileMap->insert(std::make_pair(currentCallToken, 307 | std::vector{sliceProf})); 308 | } 309 | if (!funcNameAndCurrArgumentPos.empty()) ++funcNameAndCurrArgumentPos.back().second; 310 | } 311 | } 312 | } else if (typeid(ParamTypePolicy) == typeid(*policy)) { 313 | paramdata = *policy->Data(); 314 | //record parameter data-- this is done exact as it is done for decl_stmts except there's no initializer 315 | auto sliceProfileItr = profileMap->find(paramdata.nameOfIdentifier); 316 | //Just add new slice profile if name already exists. Otherwise, add new entry in map. 317 | if (sliceProfileItr != profileMap->end()) { 318 | auto sliceProf = SliceProfile(paramdata.nameOfIdentifier, paramdata.lineNumber, 319 | (paramdata.isPointer || paramdata.isReference), true, 320 | std::set{paramdata.lineNumber}); 321 | sliceProf.containsDeclaration = true; 322 | sliceProf.nameOfContainingClass = ctx.currentClassName; 323 | sliceProfileItr->second.push_back(std::move(sliceProf)); 324 | } else { 325 | auto sliceProf = SliceProfile(paramdata.nameOfIdentifier, paramdata.lineNumber, 326 | (paramdata.isPointer || paramdata.isReference), true, 327 | std::set{paramdata.lineNumber}); 328 | sliceProf.containsDeclaration = true; 329 | sliceProf.nameOfContainingClass = ctx.currentClassName; 330 | profileMap->insert(std::make_pair(paramdata.nameOfIdentifier, 331 | std::vector{std::move(sliceProf)})); 332 | } 333 | paramdata.clear(); 334 | } else if (typeid(FunctionSignaturePolicy) == typeid(*policy)) { 335 | functionsigdata = *policy->Data(); 336 | functionSigMap.insert( 337 | std::make_pair(functionsigdata.name, 338 | functionsigdata)); 339 | } 340 | } 341 | 342 | void NotifyWrite(const PolicyDispatcher *policy, srcSAXEventDispatch::srcSAXEventContext &ctx) {} 343 | 344 | auto ArgumentProfile(std::pair func, int paramIndex, std::unordered_set visit_func) { 345 | auto Spi = profileMap->find(func.second.parameters.at(paramIndex).nameOfIdentifier); 346 | for (auto param : func.second.parameters) { 347 | if (profileMap->find(param.nameOfIdentifier)->second.back().visited) { 348 | return Spi; 349 | } else { 350 | for (auto cfunc : profileMap->find(param.nameOfIdentifier)->second.back().cfunctions) { 351 | if (cfunc.first.compare(func.first) != 0) { 352 | auto function = functionSigMap.find(cfunc.first); 353 | if (function != functionSigMap.end()) { 354 | if (cfunc.first.compare(function->first) == 0 && visit_func.find(cfunc.first) == visit_func.end()) { 355 | visit_func.insert(cfunc.first); 356 | auto recursiveSpi = ArgumentProfile(*function, std::atoi(cfunc.second.c_str()) - 1, visit_func); 357 | if (profileMap->find(param.nameOfIdentifier) != profileMap->end() && 358 | profileMap->find(recursiveSpi->first) != profileMap->end()) { 359 | profileMap->find(param.nameOfIdentifier)->second.back().definitions.insert( 360 | recursiveSpi->second.back().definitions.begin(), 361 | recursiveSpi->second.back().definitions.end()); 362 | profileMap->find(param.nameOfIdentifier)->second.back().uses.insert( 363 | recursiveSpi->second.back().uses.begin(), 364 | recursiveSpi->second.back().uses.end()); 365 | profileMap->find(param.nameOfIdentifier)->second.back().cfunctions.insert( 366 | profileMap->find( 367 | param.nameOfIdentifier)->second.back().cfunctions.begin(), 368 | recursiveSpi->second.back().cfunctions.begin(), 369 | recursiveSpi->second.back().cfunctions.end()); 370 | profileMap->find(param.nameOfIdentifier)->second.back().aliases.insert( 371 | recursiveSpi->second.back().aliases.begin(), 372 | recursiveSpi->second.back().aliases.end()); 373 | profileMap->find(param.nameOfIdentifier)->second.back().dvars.insert( 374 | recursiveSpi->second.back().dvars.begin(), 375 | recursiveSpi->second.back().dvars.end()); 376 | } 377 | } 378 | } 379 | } 380 | } 381 | profileMap->find(param.nameOfIdentifier)->second.back().visited = true; 382 | } 383 | } 384 | return Spi; 385 | } 386 | 387 | void ComputeInterprocedural() { 388 | std::unordered_set visited_func; 389 | for (std::pair> var : *profileMap) { 390 | if (!profileMap->find(var.first)->second.back().visited) { 391 | if (!var.second.back().cfunctions.empty()) { 392 | for (auto cfunc : var.second.back().cfunctions) { 393 | auto funcIt = functionSigMap.find(cfunc.first); 394 | if(funcIt != functionSigMap.end()) { 395 | if (cfunc.first.compare(funcIt->first) == 0) { //TODO fix for case: Overload 396 | auto Spi = ArgumentProfile(*funcIt, std::atoi(cfunc.second.c_str()) - 1, visited_func); 397 | if (profileMap->find(var.first) != profileMap->end() && 398 | profileMap->find(Spi->first) != profileMap->end()) { 399 | profileMap->find(var.first)->second.back().definitions.insert( 400 | Spi->second.back().definitions.begin(), 401 | Spi->second.back().definitions.end()); 402 | profileMap->find(var.first)->second.back().uses.insert( 403 | Spi->second.back().uses.begin(), 404 | Spi->second.back().uses.end()); 405 | profileMap->find(var.first)->second.back().cfunctions.insert( 406 | profileMap->find(var.first)->second.back().cfunctions.begin(), 407 | Spi->second.back().cfunctions.begin(), 408 | Spi->second.back().cfunctions.end()); 409 | profileMap->find(var.first)->second.back().aliases.insert( 410 | Spi->second.back().aliases.begin(), 411 | Spi->second.back().aliases.end()); 412 | profileMap->find(var.first)->second.back().dvars.insert( 413 | Spi->second.back().dvars.begin(), 414 | Spi->second.back().dvars.end()); 415 | } 416 | } 417 | } 418 | } 419 | } 420 | profileMap->find(var.first)->second.back().visited = true; 421 | } 422 | } 423 | } 424 | 425 | void ComputeControlPaths() { 426 | for (std::pair> var : *profileMap) { 427 | std::vector sLines; 428 | std::merge(var.second.back().definitions.begin(), var.second.back().definitions.end(), 429 | var.second.back().uses.begin(), var.second.back().uses.end(), 430 | std::inserter(sLines, sLines.begin())); 431 | for (auto loop : loopdata) { 432 | int predecessor = 0; 433 | int falseSuccessor = 0; 434 | int trueSuccessor = loop.second; 435 | bool trueSuccessorExists = false; 436 | for (auto sl : sLines) { 437 | if (sl <= loop.first) { 438 | predecessor = sl; 439 | } 440 | if (sl >= loop.first) { 441 | falseSuccessor = sl; 442 | } 443 | for (auto firstLine : sLines) { 444 | if (firstLine >= loop.first && firstLine <= loop.second && firstLine <= trueSuccessor) { 445 | trueSuccessor = firstLine; 446 | trueSuccessorExists = true; 447 | } 448 | } 449 | } 450 | if (predecessor < falseSuccessor) { 451 | if (trueSuccessorExists) { 452 | profileMap->find(var.first)->second.back().controlEdges.insert( 453 | std::make_pair(predecessor, trueSuccessor)); 454 | } 455 | profileMap->find(var.first)->second.back().controlEdges.insert( 456 | std::make_pair(predecessor, falseSuccessor)); 457 | } 458 | } 459 | int prevSL = 0; 460 | for (int i = 0; i < sLines.size(); i++) { 461 | if (i + 1 < sLines.size()) { 462 | bool outIf = true; 463 | bool outElse = true; 464 | for (auto ifblock : ifdata) { 465 | if (sLines[i] >= ifblock.first && sLines[i] <= ifblock.second) { 466 | outIf = false; 467 | break; 468 | } 469 | } 470 | if (!outIf) { 471 | for (auto elseblock : elsedata) { 472 | if (sLines[i + 1] >= elseblock.first && sLines[i + 1] <= elseblock.second) { 473 | outElse = false; 474 | break; 475 | } 476 | } 477 | } 478 | if ((outIf || outElse) && sLines[i] != sLines[i + 1]) { 479 | profileMap->find(var.first)->second.back().controlEdges.insert( 480 | std::make_pair(sLines[i], sLines[i + 1])); 481 | } 482 | } 483 | bool outControlBlock = true; 484 | for (auto loop : loopdata) { 485 | if (sLines[i] >= loop.first && sLines[i] <= loop.second) { 486 | outControlBlock = false; 487 | break; 488 | } 489 | } 490 | if (outControlBlock) { 491 | for (auto ifblock : ifdata) { 492 | if (sLines[i] >= ifblock.first && sLines[i] <= ifblock.second) { 493 | outControlBlock = false; 494 | break; 495 | } 496 | } 497 | } 498 | if (outControlBlock) { 499 | for (auto elseblock : elsedata) { 500 | if (sLines[i] >= elseblock.first && sLines[i] <= elseblock.second) { 501 | outControlBlock = false; 502 | break; 503 | } 504 | } 505 | } 506 | if (outControlBlock) { 507 | if (prevSL == 0) { 508 | prevSL = sLines[i]; 509 | } else { 510 | profileMap->find(var.first)->second.back().controlEdges.insert( 511 | std::make_pair(prevSL, sLines[i])); 512 | prevSL = 0; 513 | } 514 | } 515 | } 516 | } 517 | } 518 | 519 | protected: 520 | void *DataInner() const override { 521 | return (void *) 0; // export profile to listeners 522 | } 523 | 524 | private: 525 | DeclTypePolicy declPolicy; 526 | DeclData decldata; 527 | 528 | ParamTypePolicy paramPolicy; 529 | DeclData paramdata; 530 | 531 | InitPolicy initPolicy; 532 | InitPolicy::InitDataSet initDataSet; 533 | 534 | ExprPolicy::ExprDataSet exprDataSet; 535 | ExprPolicy exprPolicy; 536 | 537 | CallPolicy callPolicy; 538 | CallPolicy::CallData calldata; 539 | 540 | FunctionSignaturePolicy functionPolicy; 541 | SignatureData functionsigdata; 542 | std::map functionSigMap; 543 | std::string currentExprName; 544 | std::vector declDvars; 545 | 546 | std::vector> loopdata; 547 | std::vector> ifdata; 548 | std::vector> elsedata; 549 | int startLine; 550 | int endLine; 551 | 552 | std::string currentName; 553 | 554 | void InitializeEventHandlers() { 555 | using namespace srcSAXEventDispatch; 556 | closeEventMap[ParserState::op] = [this](srcSAXEventContext &ctx) { 557 | if (ctx.currentToken == "=") { 558 | currentName = currentExprName; 559 | } 560 | }; 561 | openEventMap[ParserState::declstmt] = [this](srcSAXEventContext &ctx) { 562 | ctx.dispatcher->AddListenerDispatch(&declPolicy); 563 | }; 564 | openEventMap[ParserState::parameterlist] = [this](srcSAXEventContext &ctx) { 565 | ctx.dispatcher->AddListenerDispatch(¶mPolicy); 566 | }; 567 | openEventMap[ParserState::exprstmt] = [this](srcSAXEventContext &ctx) { 568 | ctx.dispatcher->AddListenerDispatch(&exprPolicy); 569 | }; 570 | openEventMap[ParserState::call] = [this](srcSAXEventContext &ctx) { 571 | //don't want multiple callPolicy parsers running 572 | if (ctx.NumCurrentlyOpen(ParserState::call) < 2) { 573 | ctx.dispatcher->AddListenerDispatch(&callPolicy); 574 | } 575 | }; 576 | openEventMap[ParserState::init] = [this](srcSAXEventContext &ctx) { 577 | ctx.dispatcher->AddListenerDispatch(&initPolicy); 578 | }; 579 | closeEventMap[ParserState::call] = [this](srcSAXEventContext &ctx) { 580 | if (ctx.NumCurrentlyOpen(ParserState::call) < 2) { 581 | ctx.dispatcher->RemoveListenerDispatch(&callPolicy); 582 | } 583 | }; 584 | closeEventMap[ParserState::declstmt] = [this](srcSAXEventContext &ctx) { 585 | ctx.dispatcher->RemoveListenerDispatch(&declPolicy); 586 | currentName.clear(); 587 | }; 588 | closeEventMap[ParserState::exprstmt] = [this](srcSAXEventContext &ctx) { 589 | ctx.dispatcher->RemoveListenerDispatch(&exprPolicy); 590 | currentName.clear(); 591 | }; 592 | closeEventMap[ParserState::init] = [this](srcSAXEventContext &ctx) { 593 | ctx.dispatcher->RemoveListenerDispatch(&initPolicy); 594 | }; 595 | closeEventMap[ParserState::parameterlist] = [this](srcSAXEventContext &ctx) { 596 | ctx.dispatcher->RemoveListenerDispatch(¶mPolicy); 597 | }; 598 | openEventMap[ParserState::function] = [this](srcSAXEventContext &ctx) { 599 | ctx.dispatcher->AddListenerDispatch(&functionPolicy); 600 | }; 601 | openEventMap[ParserState::functionblock] = [this](srcSAXEventContext &ctx) { 602 | ctx.dispatcher->RemoveListenerDispatch(&functionPolicy); 603 | }; 604 | openEventMap[ParserState::forstmt] = [this](srcSAXEventContext &ctx) { 605 | startLine = ctx.currentLineNumber; 606 | }; 607 | closeEventMap[ParserState::forstmt] = [this](srcSAXEventContext &ctx) { 608 | endLine = ctx.currentLineNumber; 609 | loopdata.push_back(std::make_pair(startLine, endLine)); 610 | }; 611 | openEventMap[ParserState::whilestmt] = [this](srcSAXEventContext &ctx) { 612 | startLine = ctx.currentLineNumber; 613 | }; 614 | closeEventMap[ParserState::whilestmt] = [this](srcSAXEventContext &ctx) { 615 | endLine = ctx.currentLineNumber; 616 | loopdata.push_back(std::make_pair(startLine, endLine)); 617 | }; 618 | openEventMap[ParserState::ifstmt] = [this](srcSAXEventContext &ctx) { 619 | startLine = ctx.currentLineNumber; 620 | }; 621 | closeEventMap[ParserState::ifstmt] = [this](srcSAXEventContext &ctx) { 622 | endLine = ctx.currentLineNumber; 623 | ifdata.push_back(std::make_pair(startLine, endLine)); 624 | }; 625 | openEventMap[ParserState::elseif] = [this](srcSAXEventContext &ctx) { 626 | startLine = ctx.currentLineNumber; 627 | }; 628 | closeEventMap[ParserState::elseif] = [this](srcSAXEventContext &ctx) { 629 | endLine = ctx.currentLineNumber; 630 | elsedata.push_back(std::make_pair(startLine, endLine)); 631 | }; 632 | openEventMap[ParserState::elsestmt] = [this](srcSAXEventContext &ctx) { 633 | startLine = ctx.currentLineNumber; 634 | }; 635 | closeEventMap[ParserState::elsestmt] = [this](srcSAXEventContext &ctx) { 636 | endLine = ctx.currentLineNumber; 637 | elsedata.push_back(std::make_pair(startLine, endLine)); 638 | }; 639 | closeEventMap[ParserState::tokenstring] = [this](srcSAXEventContext &ctx) { 640 | //TODO: possibly, this if-statement is suppressing more than just unmarked whitespace. Investigate. 641 | if (!(ctx.currentToken.empty() || ctx.currentToken == " ")) { 642 | if (ctx.And({ParserState::name, ParserState::expr, ParserState::exprstmt}) && 643 | ctx.Nor({ParserState::specifier, ParserState::modifier, ParserState::op})) { 644 | currentExprName = ctx.currentToken; 645 | } 646 | } 647 | }; 648 | closeEventMap[ParserState::archive] = [this](srcSAXEventContext &ctx) { 649 | for (std::unordered_map>::iterator it = profileMap->begin(); 650 | it != profileMap->end(); ++it) { 651 | for (std::vector::iterator sIt = it->second.begin(); sIt != it->second.end(); ++sIt) { 652 | if (sIt->containsDeclaration) { 653 | std::vector::iterator sIt2 = it->second.begin(); 654 | while (sIt2 != it->second.end()) { 655 | if (!sIt2->containsDeclaration) { 656 | std::cout << "NAME: " << sIt2->variableName << std::endl; 657 | sIt->uses.insert(sIt2->uses.begin(), sIt2->uses.end()); 658 | sIt->definitions.insert(sIt2->definitions.begin(), sIt2->definitions.end()); 659 | sIt->dvars.insert(sIt2->dvars.begin(), sIt2->dvars.end()); 660 | sIt->aliases.insert(sIt2->aliases.begin(), sIt2->aliases.end()); 661 | sIt->cfunctions.reserve(sIt->cfunctions.size() + sIt2->cfunctions.size()); 662 | sIt->cfunctions.insert(sIt->cfunctions.end(), sIt2->cfunctions.begin(), 663 | sIt2->cfunctions.end()); 664 | sIt2 = it->second.erase(sIt2); 665 | sIt = sIt2; 666 | } else { 667 | ++sIt2; 668 | } 669 | } 670 | } 671 | } 672 | } 673 | ComputeControlPaths(); 674 | ComputeInterprocedural(); 675 | }; 676 | } 677 | }; 678 | 679 | 680 | #endif 681 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB DISPATCHER_SOURCE dispatcher/*.cpp) 2 | file(GLOB DISPATCHER_HEADER dispatcher/*.hpp) 3 | 4 | file(GLOB SLICE_SOURCE *.cpp) 5 | 6 | add_executable(testsrcslice ${DISPATCHER_SOURCE} ${DISPATCHER_HEADER} ${SLICE_SOURCE}) 7 | 8 | target_link_libraries(testsrcslice gtest_main gtest srcsax_static srcml srcsaxeventdispatch ${GTEST_LIBRARIES} ${LIBXML2_LIBRARIES} pthread) -------------------------------------------------------------------------------- /test/srcslicetest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::string StringToSrcML(std::string str){ 10 | struct srcml_archive* archive; 11 | struct srcml_unit* unit; 12 | size_t size = 0; 13 | 14 | char *ch = 0; 15 | 16 | archive = srcml_archive_create(); 17 | srcml_archive_enable_option(archive, SRCML_OPTION_POSITION); 18 | srcml_archive_write_open_memory(archive, &ch, &size); 19 | 20 | unit = srcml_unit_create(archive); 21 | srcml_unit_set_language(unit, SRCML_LANGUAGE_CXX); 22 | srcml_unit_set_filename(unit, "testsrcType.cpp"); 23 | 24 | srcml_unit_parse_memory(unit, str.c_str(), str.size()); 25 | srcml_archive_write_unit(archive, unit); 26 | 27 | srcml_unit_free(unit); 28 | srcml_archive_close(archive); 29 | srcml_archive_free(archive); 30 | 31 | ch[size-1] = 0; 32 | 33 | return std::string(ch); 34 | } 35 | 36 | namespace { 37 | class TestsrcSliceDeclPolicy : public ::testing::Test{ 38 | public: 39 | std::unordered_map> profileMap; 40 | TestsrcSliceDeclPolicy(){ 41 | 42 | } 43 | void SetUp(){ 44 | std::string str = "int main(){Object coo = 5; const Object ke_e4e = 5; static const Object caa34 = 5; Object coo = 5; Object coo = 5;}"; 45 | std::string srcmlStr = StringToSrcML(str); 46 | 47 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 48 | srcSAXController control(srcmlStr); 49 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 50 | control.parse(&handler); 51 | } 52 | void TearDown(){ 53 | 54 | } 55 | ~TestsrcSliceDeclPolicy(){ 56 | 57 | } 58 | }; 59 | } 60 | 61 | TEST_F(TestsrcSliceDeclPolicy, TestDetectCommonDeclarations) { 62 | const int NUM_DECLARATIONS = 3; 63 | EXPECT_EQ(profileMap.size(), NUM_DECLARATIONS); 64 | } 65 | 66 | TEST_F(TestsrcSliceDeclPolicy, TestDetectCommonDeclarationsWithClone) { 67 | const int NUM_CLONES = 3; 68 | EXPECT_EQ(profileMap.find("coo")->second.size(), NUM_CLONES); 69 | } 70 | 71 | namespace { 72 | class TestsrcSliceExprPolicy : public ::testing::Test{ 73 | public: 74 | std::unordered_map> profileMap; 75 | TestsrcSliceExprPolicy(){ 76 | 77 | } 78 | void SetUp(){ 79 | std::string str = "void foo(){j = 0; k = 1; doreme = 5; abc = abc + 0; i = j + k;}"; 80 | std::string srcmlStr = StringToSrcML(str); 81 | 82 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 83 | srcSAXController control(srcmlStr); 84 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 85 | control.parse(&handler); 86 | } 87 | void TearDown(){ 88 | 89 | } 90 | ~TestsrcSliceExprPolicy(){ 91 | 92 | } 93 | }; 94 | } 95 | 96 | TEST_F(TestsrcSliceExprPolicy, TestDetectCommonExpr) { 97 | const int NUM_EXPR = 5; 98 | EXPECT_EQ(profileMap.size(), NUM_EXPR); 99 | } 100 | 101 | TEST_F(TestsrcSliceExprPolicy, TestDetectCommonExprWithClone) { 102 | const int NUM_CLONES_SHOULD_NOT_INCREASE = 1; 103 | EXPECT_EQ(profileMap.find("j")->second.size(), NUM_CLONES_SHOULD_NOT_INCREASE); 104 | } 105 | 106 | namespace { 107 | class TestsrcSliceDeclExprUnion : public ::testing::Test{ 108 | public: 109 | std::unordered_map> profileMap; 110 | TestsrcSliceDeclExprUnion(){ 111 | 112 | } 113 | void SetUp(){ 114 | std::string str = 115 | "int main(){\n" 116 | "Object coo = 5;\n" 117 | "const Object ke_e4e = 5;\n" 118 | "ke_e4e = coo;\n" 119 | "caa34 = caa34 + 5;\n" 120 | "coo = ke_e4e + caa34;\n" 121 | "}\n"; 122 | std::string srcmlStr = StringToSrcML(str); 123 | 124 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 125 | srcSAXController control(srcmlStr); 126 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 127 | control.parse(&handler); 128 | } 129 | void TearDown(){ 130 | 131 | } 132 | ~TestsrcSliceDeclExprUnion(){ 133 | 134 | } 135 | }; 136 | } 137 | 138 | TEST_F(TestsrcSliceDeclExprUnion, TestDetectCommonExpr) { 139 | const int NUM_DECL_AND_EXPR = 3; 140 | EXPECT_EQ(profileMap.size(), NUM_DECL_AND_EXPR); 141 | } 142 | 143 | TEST_F(TestsrcSliceDeclExprUnion, TestDetectCommonUseDefke_e4e) { 144 | const int LINE_NUM_USE_OF_KE_E4E = 6; 145 | const int LINE_NUM_EXPR_DEF_OF_KE_E4E = 4; 146 | const int LINE_NUM_DECL_DEFS_OF_KE_E4E = 3; 147 | 148 | auto exprIt = profileMap.find("ke_e4e"); 149 | 150 | EXPECT_TRUE(exprIt->second.back().uses.find(LINE_NUM_USE_OF_KE_E4E) != exprIt->second.back().uses.end()); 151 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_EXPR_DEF_OF_KE_E4E) != exprIt->second.back().definitions.end()); 152 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_DECL_DEFS_OF_KE_E4E) != exprIt->second.back().definitions.end()); 153 | } 154 | 155 | TEST_F(TestsrcSliceDeclExprUnion, TestDetectCommonUseDefcaa34) { 156 | const int FIRST_LINE_NUM_USE_OF_CAA34 = 5; 157 | const int SECOND_LINE_NUM_USE_OF_CAA34 = 6; 158 | 159 | auto exprIt = profileMap.find("caa34"); 160 | 161 | EXPECT_TRUE(exprIt->second.back().definitions.find(FIRST_LINE_NUM_USE_OF_CAA34) != exprIt->second.back().definitions.end()); 162 | EXPECT_TRUE(exprIt->second.back().uses.find(SECOND_LINE_NUM_USE_OF_CAA34) != exprIt->second.back().uses.end()); 163 | EXPECT_TRUE(exprIt->second.back().uses.find(FIRST_LINE_NUM_USE_OF_CAA34) != exprIt->second.back().uses.end()); 164 | } 165 | 166 | namespace { 167 | class TestsrcSliceCallPolicy : public ::testing::Test{ 168 | public: 169 | std::unordered_map> profileMap; 170 | TestsrcSliceCallPolicy(){ 171 | 172 | } 173 | void SetUp(){ 174 | std::string str = 175 | "int main(){\n" 176 | "Foo(a,b);\n" 177 | "Bar(Foo(c,d));\n" 178 | "}\n"; 179 | std::string srcmlStr = StringToSrcML(str); 180 | 181 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 182 | srcSAXController control(srcmlStr); 183 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 184 | control.parse(&handler); 185 | } 186 | void TearDown(){ 187 | 188 | } 189 | ~TestsrcSliceCallPolicy(){ 190 | 191 | } 192 | }; 193 | } 194 | 195 | 196 | TEST_F(TestsrcSliceCallPolicy, TestDetectCallArgumentsb) { 197 | const int CALL_USAGE_LINE = 2; 198 | const int NUM_ARGUMENTS_DETECTED = 6; //fix -- should be 4 but expr runs at same time as call 199 | auto callIt = profileMap.find("b"); 200 | 201 | EXPECT_TRUE(callIt->second.back().definitions.find(CALL_USAGE_LINE) != callIt->second.back().uses.end()); 202 | EXPECT_EQ(profileMap.size(), NUM_ARGUMENTS_DETECTED); 203 | } 204 | TEST_F(TestsrcSliceCallPolicy, TestDetectCallCFunctionsb) { 205 | auto callIt = profileMap.find("b"); 206 | 207 | EXPECT_TRUE(callIt->second.back().cfunctions.back().first == "Foo"); 208 | EXPECT_TRUE(callIt->second.back().cfunctions.back().second == "2"); 209 | } 210 | TEST_F(TestsrcSliceCallPolicy, TestDetectCallArgumentsc) { 211 | const int CALL_USAGE_LINE = 3; 212 | auto callIt = profileMap.find("c"); 213 | 214 | EXPECT_TRUE(callIt->second.back().definitions.find(CALL_USAGE_LINE) != callIt->second.back().uses.end()); 215 | } 216 | TEST_F(TestsrcSliceCallPolicy, TestDetectCallCFunctionsc) { 217 | auto callIt = profileMap.find("c"); 218 | 219 | EXPECT_TRUE(callIt->second.back().cfunctions.back().first == "Bar-Foo"); 220 | EXPECT_TRUE(callIt->second.back().cfunctions.back().second == "1-1"); 221 | } 222 | 223 | namespace { 224 | class TestsrcSliceDeclExprCallUnion : public ::testing::Test{ 225 | public: 226 | std::unordered_map> profileMap; 227 | TestsrcSliceDeclExprCallUnion(){ 228 | 229 | } 230 | void SetUp(){ 231 | std::string str = 232 | "int main(){\n" 233 | "Object b = 5;\n" 234 | "const Object ke_e4e = b;\n" 235 | "ke_e4e = coo + Bar(Foo(b));\n" 236 | "caa34 = caa34 + Foo(ke_e4e, b);\n" 237 | "coo = ke_e4e + caa34;\n" 238 | "const Object test = i-Bam(b,a);\n" 239 | "}\n"; 240 | std::string srcmlStr = StringToSrcML(str); 241 | 242 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 243 | srcSAXController control(srcmlStr); 244 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 245 | control.parse(&handler); 246 | } 247 | void TearDown(){ 248 | 249 | } 250 | ~TestsrcSliceDeclExprCallUnion(){ 251 | 252 | } 253 | }; 254 | } 255 | 256 | TEST_F(TestsrcSliceDeclExprCallUnion, TestDetectCallDeclExprUnionke_e4e) { 257 | const int FIRST_LINE_NUM_USE_OF_KE_E4E = 5; 258 | const int SECOND_LINE_NUM_USE_OF_KE_E4E = 6; 259 | const int LINE_NUM_EXPR_DEF_OF_KE_E4E = 4; 260 | const int LINE_NUM_DECL_DEFS_OF_KE_E4E = 3; 261 | 262 | auto exprIt = profileMap.find("ke_e4e"); 263 | 264 | EXPECT_TRUE(exprIt->second.back().uses.find(FIRST_LINE_NUM_USE_OF_KE_E4E) != exprIt->second.back().uses.end()); 265 | EXPECT_TRUE(exprIt->second.back().uses.find(SECOND_LINE_NUM_USE_OF_KE_E4E) != exprIt->second.back().uses.end()); 266 | 267 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_EXPR_DEF_OF_KE_E4E) != exprIt->second.back().definitions.end()); 268 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_DECL_DEFS_OF_KE_E4E) != exprIt->second.back().definitions.end()); 269 | } 270 | 271 | TEST_F(TestsrcSliceDeclExprCallUnion, TestDetectCallDeclExprUnionb) { 272 | const int FIRST_LINE_NUM_USE_OF_b = 4; 273 | const int SECOND_LINE_NUM_USE_OF_b = 5; 274 | const int THIRD_LINE_NUM_USE_OF_b = 3; 275 | const int FIRST_LINE_NUM_DEF_OF_b = 2; 276 | const int FOURTH_LINE_NUM_DEF_OF_b = 7; 277 | 278 | auto exprIt = profileMap.find("b"); 279 | 280 | EXPECT_TRUE(exprIt->second.back().uses.find(FIRST_LINE_NUM_USE_OF_b) != exprIt->second.back().uses.end()); 281 | EXPECT_TRUE(exprIt->second.back().uses.find(SECOND_LINE_NUM_USE_OF_b) != exprIt->second.back().uses.end()); 282 | EXPECT_TRUE(exprIt->second.back().uses.find(THIRD_LINE_NUM_USE_OF_b) != exprIt->second.back().uses.end()); 283 | EXPECT_TRUE(exprIt->second.back().uses.find(FOURTH_LINE_NUM_DEF_OF_b) != exprIt->second.back().uses.end()); 284 | 285 | EXPECT_TRUE(exprIt->second.back().cfunctions.front().first == "Bar-Foo"); 286 | EXPECT_TRUE(exprIt->second.back().cfunctions.front().second == "1-1"); 287 | 288 | EXPECT_TRUE(exprIt->second.back().cfunctions.at(1).first == "Foo"); 289 | EXPECT_TRUE(exprIt->second.back().cfunctions.at(1).second == "2"); 290 | 291 | EXPECT_TRUE(exprIt->second.back().cfunctions.back().first == "Bam"); 292 | EXPECT_TRUE(exprIt->second.back().cfunctions.back().second == "1"); 293 | 294 | EXPECT_TRUE(exprIt->second.back().definitions.find(FIRST_LINE_NUM_DEF_OF_b) != exprIt->second.back().uses.end()); 295 | } 296 | 297 | TEST_F(TestsrcSliceDeclExprCallUnion, TestDetectCallDeclExprUnionDvarske_e4e) { 298 | auto exprIt = profileMap.find("ke_e4e"); 299 | 300 | EXPECT_TRUE(exprIt->second.back().dvars.find("coo") != exprIt->second.back().dvars.end()); 301 | EXPECT_TRUE(exprIt->second.back().dvars.find("caa34") != exprIt->second.back().dvars.end()); 302 | } 303 | 304 | TEST_F(TestsrcSliceDeclExprCallUnion, TestDetectCallDeclExprUnionDvarscaa34) { 305 | auto exprIt = profileMap.find("caa34"); 306 | 307 | EXPECT_TRUE(exprIt->second.back().dvars.find("caa34") != exprIt->second.back().dvars.end()); 308 | EXPECT_TRUE(exprIt->second.back().dvars.find("coo") != exprIt->second.back().dvars.end()); 309 | } 310 | 311 | TEST_F(TestsrcSliceDeclExprCallUnion, TestDetectCallDeclExprUnionDvarsb) { 312 | auto exprIt = profileMap.find("b"); 313 | 314 | EXPECT_TRUE(exprIt->second.back().dvars.find("ke_e4e") != exprIt->second.back().dvars.end()); 315 | EXPECT_TRUE(exprIt->second.back().dvars.find("caa34") != exprIt->second.back().dvars.end()); 316 | EXPECT_TRUE(exprIt->second.back().dvars.find("test") != exprIt->second.back().dvars.end()); 317 | } 318 | namespace { 319 | class TestsrcSliceAliasDetection : public ::testing::Test{ 320 | public: 321 | std::unordered_map> profileMap; 322 | TestsrcSliceAliasDetection(){ 323 | 324 | } 325 | void SetUp(){ 326 | std::string str = 327 | "int main(){\n" 328 | "Object* b = 0;\n" 329 | "b = ke_e4e;\n" 330 | "Object* a = &ke_e4e;\n" 331 | "b = ke_e4e;\n" 332 | "float* e = b;\n" 333 | "}\n"; 334 | std::string srcmlStr = StringToSrcML(str); 335 | 336 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 337 | srcSAXController control(srcmlStr); 338 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 339 | control.parse(&handler); 340 | } 341 | void TearDown(){ 342 | 343 | } 344 | ~TestsrcSliceAliasDetection(){ 345 | 346 | } 347 | }; 348 | } 349 | 350 | TEST_F(TestsrcSliceAliasDetection, TestAliases) { 351 | 352 | auto exprIt = profileMap.find("ke_e4e"); 353 | 354 | EXPECT_TRUE(exprIt->second.back().aliases.find("b") != exprIt->second.back().aliases.end()); 355 | EXPECT_TRUE(exprIt->second.back().aliases.find("a") != exprIt->second.back().aliases.end()); 356 | } 357 | 358 | namespace { 359 | class TestParamSliceDetection : public ::testing::Test{ 360 | public: 361 | std::unordered_map> profileMap; 362 | TestParamSliceDetection(){ 363 | 364 | } 365 | void SetUp(){ 366 | std::string str = 367 | "int main(int k, double* j, float l[]){\n" 368 | "j = k;\n" 369 | "l = 0;\n" 370 | "}\n"; 371 | std::string srcmlStr = StringToSrcML(str); 372 | 373 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 374 | srcSAXController control(srcmlStr); 375 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 376 | control.parse(&handler); 377 | } 378 | void TearDown(){ 379 | 380 | } 381 | ~TestParamSliceDetection(){ 382 | 383 | } 384 | }; 385 | } 386 | 387 | TEST_F(TestParamSliceDetection, TestParamsK) { 388 | const int LINE_NUM_DEF_OF_K = 1; 389 | const int LINE_NUM_USE_OF_K = 2; 390 | auto exprIt = profileMap.find("k"); 391 | 392 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_DEF_OF_K) != exprIt->second.back().definitions.end()); 393 | EXPECT_TRUE(exprIt->second.back().uses.find(LINE_NUM_USE_OF_K) != exprIt->second.back().uses.end()); 394 | EXPECT_TRUE(exprIt->second.back().aliases.find("j") != exprIt->second.back().aliases.end()); 395 | } 396 | TEST_F(TestParamSliceDetection, TestParamsJ) { 397 | const int LINE_NUM_DEF_OF_J = 1; 398 | const int LINE_NUM_SECOND_DEF_OF_J = 2; 399 | auto exprIt = profileMap.find("j"); 400 | 401 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_DEF_OF_J) != exprIt->second.back().definitions.end()); 402 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_SECOND_DEF_OF_J) != exprIt->second.back().definitions.end()); 403 | EXPECT_TRUE(exprIt->second.back().potentialAlias); 404 | } 405 | TEST_F(TestParamSliceDetection, TestParamsL) { 406 | const int LINE_NUM_DEF_OF_L = 1; 407 | const int LINE_NUM_SECOND_DEF_OF_L = 3; 408 | auto exprIt = profileMap.find("l"); 409 | 410 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_DEF_OF_L) != exprIt->second.back().definitions.end()); 411 | EXPECT_TRUE(exprIt->second.back().definitions.find(LINE_NUM_SECOND_DEF_OF_L) != exprIt->second.back().definitions.end()); 412 | } 413 | 414 | namespace { 415 | class TestComputeInterprocedural : public ::testing::Test{ 416 | public: 417 | std::unordered_map> profileMap; 418 | TestComputeInterprocedural(){ 419 | 420 | } 421 | void SetUp(){ 422 | std::string str = 423 | "void fun(int z){\n" 424 | "z++;\n" 425 | "}\n" 426 | "void foo(int &x, int &y){\n" 427 | "fun(x);\n" 428 | "y++;\n" 429 | "}\n" 430 | "int main() {\n" 431 | "int sum = 0;\n" 432 | "int i = sum;\n" 433 | "while(i<=10){\n" 434 | "foo(sum, i);\n" 435 | "}\n" 436 | "std::cout< handler({cat}); 443 | control.parse(&handler); 444 | } 445 | void TearDown(){ 446 | 447 | } 448 | ~TestComputeInterprocedural(){ 449 | 450 | } 451 | }; 452 | } 453 | 454 | TEST_F(TestComputeInterprocedural, TestSLines) { 455 | for(auto use : profileMap.find("x")->second.back().uses){ 456 | EXPECT_TRUE(profileMap.find("sum")->second.back().uses.find(use) != profileMap.find("sum")->second.back().uses.end()); 457 | } 458 | for(auto def : profileMap.find("x")->second.back().definitions){ 459 | EXPECT_TRUE(profileMap.find("sum")->second.back().definitions.find(def) != profileMap.find("sum")->second.back().definitions.end()); 460 | } 461 | } 462 | 463 | namespace { 464 | class TestComputeInterproceduralMultipleNestings : public ::testing::Test{ 465 | public: 466 | std::unordered_map> profileMap; 467 | TestComputeInterproceduralMultipleNestings(){ 468 | 469 | } 470 | void SetUp(){ 471 | std::string str = 472 | "void fun(int z);\n" 473 | "\n" 474 | "void loop(int a) {\n" 475 | " a++;\n" 476 | " fun(a);\n" 477 | "}\n" 478 | "\n" 479 | "void fun(int z) {\n" 480 | " if(z < 10) {\n" 481 | " loop(z);\n" 482 | " }\n" 483 | "}\n" 484 | "\n" 485 | "void bar(int y) {\n" 486 | " fun(y);\n" 487 | "}\n" 488 | "\n" 489 | "void foo(int &x) {\n" 490 | " bar(x);\n" 491 | "}\n" 492 | "\n" 493 | "int main() {\n" 494 | " int sum = 0;\n" 495 | " foo(sum);\n" 496 | "}"; 497 | std::string srcmlStr = StringToSrcML(str); 498 | 499 | SrcSlicePolicy* cat = new SrcSlicePolicy(&profileMap); 500 | srcSAXController control(srcmlStr); 501 | srcSAXEventDispatch::srcSAXEventDispatcher<> handler({cat}); 502 | control.parse(&handler); 503 | } 504 | void TearDown(){ 505 | 506 | } 507 | ~TestComputeInterproceduralMultipleNestings(){ 508 | 509 | } 510 | }; 511 | } 512 | 513 | TEST_F(TestComputeInterproceduralMultipleNestings, TestSLines) { 514 | for(auto use : profileMap.find("x")->second.back().uses){ 515 | EXPECT_TRUE(profileMap.find("sum")->second.back().uses.find(use) != profileMap.find("sum")->second.back().uses.end()); 516 | } 517 | for(auto def : profileMap.find("x")->second.back().definitions){ 518 | EXPECT_TRUE(profileMap.find("sum")->second.back().definitions.find(def) != profileMap.find("sum")->second.back().definitions.end()); 519 | } 520 | } 521 | 522 | namespace { 523 | class TestComputeControlPaths : public ::testing::Test{ 524 | public: 525 | std::unordered_map> profileMap; 526 | TestComputeControlPaths(){ 527 | 528 | } 529 | void SetUp(){ 530 | std::string str = 531 | "int main() {\n" 532 | " int sum = 0;\n" 533 | " int i = 1;\n" 534 | " while(i<=10){\n" 535 | " sum = sum + i;\n" 536 | " i++;\n" 537 | " }\n" 538 | " std::cout< handler({cat}); 546 | control.parse(&handler); 547 | } 548 | void TearDown(){ 549 | 550 | } 551 | ~TestComputeControlPaths(){ 552 | 553 | } 554 | }; 555 | } 556 | 557 | TEST_F(TestComputeControlPaths, TestSLines) { 558 | EXPECT_TRUE(profileMap.find("sum")->second.back().controlEdges.find(std::make_pair(2, 5)) != profileMap.find("sum")->second.back().controlEdges.end()); 559 | EXPECT_TRUE(profileMap.find("sum")->second.back().controlEdges.find(std::make_pair(2, 8)) != profileMap.find("sum")->second.back().controlEdges.end()); 560 | EXPECT_TRUE(profileMap.find("sum")->second.back().controlEdges.find(std::make_pair(5, 8)) != profileMap.find("sum")->second.back().controlEdges.end()); 561 | 562 | //EXPECT_TRUE(profileMap.find("i")->second.back().controlEdges.find(std::make_pair(3, 4)) != profileMap.find("i")->second.back().controlEdges.end()); 563 | //EXPECT_TRUE(profileMap.find("i")->second.back().controlEdges.find(std::make_pair(4, 5)) != profileMap.find("i")->second.back().controlEdges.end()); 564 | //EXPECT_TRUE(profileMap.find("i")->second.back().controlEdges.find(std::make_pair(4, 9)) != profileMap.find("i")->second.back().controlEdges.end()); 565 | EXPECT_TRUE(profileMap.find("i")->second.back().controlEdges.find(std::make_pair(5, 6)) != profileMap.find("i")->second.back().controlEdges.end()); 566 | EXPECT_TRUE(profileMap.find("i")->second.back().controlEdges.find(std::make_pair(6, 9)) != profileMap.find("i")->second.back().controlEdges.end()); 567 | 568 | 569 | } 570 | --------------------------------------------------------------------------------