Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added DiffParse.exe
Binary file not shown.
9 changes: 0 additions & 9 deletions Gopkg.lock

This file was deleted.

22 changes: 0 additions & 22 deletions Gopkg.toml

This file was deleted.

42 changes: 42 additions & 0 deletions Logger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "Logger.h"

using namespace std;

Logger::Logger(string path, Results *results)
{
_path = path;
_results = results;
}

void Logger::SaveToDisk()
{
ofstream file;
string filename = _path + "//diffResult.txt";
file.open(filename, ios::trunc);

if (!file.good())
throw exception(string("Could not create log file " + filename).c_str());

Log(file);
}

void Logger::Log(ostream &buf)
{
buf << "\n========== Parsed .diff files ==========\n";
for (int i = 0; i < _results->fileNames.size(); ++i)
buf << _results->fileNames.at(i) << endl;

buf << left << setw(24) << "Regions:" << _results->regions << "\n"
<< setw(24) << "Lines Added:" << _results->linesAdded << "\n"
<< setw(24) << "Lines Deleted:" << _results->linesDeleted << "\n"
<< setw(24) << "Files Count:" << _results->files.size() << "\n"
<< setw(24) << "Function Calls Count:" << _results->functionCalls.size() << "\n";

buf << "\n========== Files ==========\n";
for (int i = 0; i < _results->files.size(); ++i)
buf << _results->files.at(i) << endl;

buf << "\n========== Function Calls ==========\n";
for (int i = 0; i < _results->functionCalls.size(); ++i)
buf << setw(40) << left << _results->functionCalls.at(i).first << " (count=" << _results->functionCalls.at(i).second << ")\n";
}
16 changes: 16 additions & 0 deletions Logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "Result.h"

class Logger
{
public:
Logger(std::string path, Results *results);
void SaveToDisk();

private:
Results *_results;
std::string _path;

void Log(std::ostream &buf);
};
45 changes: 45 additions & 0 deletions Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "Parse.h"
#include "Logger.h"

#include <windows.h>
#include <experimental/filesystem>
#include <Pathcch.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")

using namespace std;

void main()
{
chrono::steady_clock::time_point start = chrono::steady_clock::now();

TCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
PathRemoveFileSpec(path);

Results results;

Parse parse(path, &results);
try
{
parse.Read();
}
catch (exception e)
{
cout << "ERROR: " << e.what() << endl;
}

Logger logger(path, &results);
try
{
logger.SaveToDisk();
}
catch (exception e)
{
cout << "ERROR: " << e.what() << endl;
}

cout << setw(24) << "Statistics logged to file: './diffResult.txt'" <<"\n";
cout << setw(24) << "Execution time:" << (int)(chrono::duration_cast<chrono::duration<double>>(chrono::steady_clock::now() - start).count() * 1000) << "ms\n";
system("pause");
}
193 changes: 193 additions & 0 deletions Parse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#include "Parse.h"

using namespace std;

Parse::Parse(string path, Results *results)
{
_path = path + "\\diffs";
_results = results;
}

void Parse::Read()
{
for (const auto& name : get_filenames())
{
ifstream currentFile;
_path = name + ".diff";
currentFile.open(_path);

if (!currentFile.good())
throw exception(string("Could not open file " + _path).c_str());

_results->fileNames.push_back(_path);

while (getline(currentFile, _line))
{
_ss = stringstream(_line);
_ss >> _token;

if (_token == "---" || _token == "+++" || _token == "index")
continue; // do nothing

if (_token == "@@")
_results->regions++;
else if (_token == "diff")
{
string git;
string fileA;
string fileB;
_ss >> git >> fileA >> fileB;

_results->files.push_back(experimental::filesystem::path(fileA).filename().string());
}
else {
if (_token == "+")
_results->linesAdded++;
else if (_token == "-")
_results->linesDeleted++;
FindFunctions();
}
}
}
}

vector<string> Parse::get_filenames()
{
vector<string> filenames;
experimental::filesystem::path path = _path;
const experimental::filesystem::directory_iterator end{};

for (experimental::filesystem::directory_iterator iter{ path }; iter != end; ++iter)
if (experimental::filesystem::is_regular_file(*iter) && iter->path().extension().string() == ".diff")
{
auto x = iter->path();
x.replace_extension("");
filenames.push_back(x.string());
}
return filenames;
}


//function call supported:
//funcName_1 (funcName_2(arg, arg2),
// arg3)
// ^ 1 ^ 2 ^ 3
//
// ^ 1: function Name : alphaALPHANumeric and _
// ^ 2 : Function call can have spaces between function name and arguments
// ^ 3 : function calls can be embedded as arguments
void Parse::FindFunctions()
{
_text = _ss.str();

if (_text.find("(") == string::npos ||
isCondition() ||
isComment())
return;

int indexOfOpenParenthese = _text.find_first_of("(");

if (isADeclaration(_text.substr(0, indexOfOpenParenthese)))
return;

//Support embeded function calls. i.e:functionCal(functioncall2(),..
string functionName = "";
while (indexOfOpenParenthese != string::npos) {
functionName = extractFunctionName(indexOfOpenParenthese);
if (functionName == "")
break;
addFunctionCall(functionName);
indexOfOpenParenthese = _text.find("(", indexOfOpenParenthese + 1);
}
}

string Parse::extractFunctionName(int indexOfOpenParenthese)
{
int indexLastCharInName;
int indexFirstCharInName;

//Allow to have a whitespaces between the functionName and "(" .
if (isspace(_text[indexOfOpenParenthese - 1]))
indexLastCharInName = findIndexBeforeSpaces(indexOfOpenParenthese);
else
indexLastCharInName = indexOfOpenParenthese;

//Decrement index to find begining of the function name
indexFirstCharInName = indexLastCharInName;
while (indexFirstCharInName > 0)
if (_text.substr(indexFirstCharInName - 1, indexLastCharInName - indexFirstCharInName + 1).find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") == std::string::npos)
indexFirstCharInName--;
else break;

string functionName = _text.substr(indexFirstCharInName, indexLastCharInName - indexFirstCharInName);

//function name can't be empty or start with digit
if (functionName.size() == 0 || isdigit(functionName[0]))
return"";

return functionName;
}


void Parse::addFunctionCall(string functionName)
{

// find function and increment counter, or add function if not found
auto x = std::find_if(_results->functionCalls.begin(), _results->functionCalls.end(), [&](const std::pair<std::string, int>& element) { return element.first == functionName; });
if (x != _results->functionCalls.end())
x[0].second++;
else
_results->functionCalls.push_back(pair<string, int>(functionName, 1));
}

bool Parse::isCondition()
{
if (_text.find("if") != string::npos ||
_text.find("for") != string::npos ||
_text.find("while") != string::npos ||
_text.find("switch") != string::npos)
return true;
return false;
}

bool Parse::isComment()
{
int index = _text.find_first_not_of("/t ");
string commentSign = _text.substr(index, 2);
if (commentSign == "//" || //cpp, Go, Java,...
commentSign == "#" || // python
commentSign == "/*") //cpp
return true;
return false;
}

bool Parse::isADeclaration(string text)
{
if(text.find("int ") != string::npos ||
text.find("double ") != string::npos ||
text.find("long ") != string::npos ||
text.find("float ") != string::npos ||
text.find("bool ") != string::npos ||
text.find("void ") != string::npos ||
text.find("function ") != string::npos || //java, javascript
text.find("def ") != string::npos || //python
text.find("func ") != string::npos) //goLang
return true;
return false;
}

int Parse::findIndexBeforeSpaces( int end )
{
int indexOfWhiteSpace = end - 1;
int indexOfFirstCharInName = end - 1;

while (indexOfFirstCharInName > 0)
if (_text.substr(indexOfFirstCharInName - 1, indexOfWhiteSpace - indexOfFirstCharInName + 1).find_first_not_of("\t ") == std::string::npos)
indexOfFirstCharInName--;
else
break;
if (indexOfFirstCharInName != 0)
return indexOfFirstCharInName;
else
return end;
}
30 changes: 30 additions & 0 deletions Parse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "Result.h"

class Parse
{
public:
Parse(std::string path, Results *results);
void Read();
void FindFunctions();

private:
std::ifstream _file;
std::string _line;
std::string _token;
std::stringstream _ss;
std::string _path;
std::string _text;

Results *_results;

std::vector<std::string> get_filenames();
bool isCondition();
bool isComment();
bool isADeclaration(std::string text);

std::string extractFunctionName(int indexOfOpenParenthese);
void addFunctionCall(std::string functionName);
int findIndexBeforeSpaces(int end);
};
21 changes: 21 additions & 0 deletions Result.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <experimental/filesystem>
#include <exception>
#include <chrono>

struct Results
{
std::vector<std::string> fileNames;
std::vector<std::string> files;
int regions = 0;
int linesAdded = 0;
int linesDeleted = 0;
std::vector<std::pair<std::string, int>> functionCalls;
};
Loading