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
68 changes: 68 additions & 0 deletions AstResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import java.util.List;
import java.util.ArrayList;

import org.json.*;

public class AstResult {

List<VariableDescription> variablesDeclarations;

public AstResult() {
this.variablesDeclarations = new ArrayList<VariableDescription>();
}

public String toString() {
StringBuffer buffer = new StringBuffer();

for (VariableDescription vd : variablesDeclarations) {
buffer.append(vd);
}
return buffer.toString();
}

public void add(String typeName, String varName) {
this.variablesDeclarations.add(new VariableDescription(typeName, varName));
}

private class VariableDescription {
String typeName;
String varName;

public VariableDescription(String typeName, String varName) {
this.typeName = typeName;
this.varName = varName;
}
public String toString() {
return String.format("{%s}{%s}\n", this.typeName, this.varName);
}
}

public void propagate(JSONObject jo) {
try {
JSONArray children = jo.getJSONArray("Children"); // get the children of the current node in the JSONObject
if (jo.get("Type").equals("VariableDeclaration")) { // check if the current node is a "VariableDeclaration"
JSONObject first_child = children.getJSONObject(0).getJSONArray("Children").getJSONObject(0);
String typeName = first_child.getString("ValueText"); // first child of a variable declaration will give the type

JSONObject second_child = children.getJSONObject(1).getJSONArray("Children").getJSONObject(0);
String varName = second_child.getString("ValueText"); // second child of a variable declaration will give the variable name

this.add(typeName, varName); // add the variable to the AstResult

for (int i = 2; children != null && i < children.length(); i++) { // goes through the rest of the children of the current node
this.propagate(children.getJSONObject(i));
}
}
else {
for (int i = 0; children != null && i < children.length(); i++) { // goes through all the children of the current node
this.propagate(children.getJSONObject(i));
}
}
}
catch(JSONException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
return;
}
}
190 changes: 190 additions & 0 deletions DiffResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import java.lang.StringBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

import java.io.File;

import java.lang.StringBuffer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.*;


public class DiffResult {
//The name of the files seen
List<String> files;
//How many region we have (i.e. seperated by @@)
int regions = 0;
//How many line were added total
int lineAdded = 0;
//How many line were deleted total
int lineDeleted = 0;
//How many times the function seen in the code are called.
Map<String, Integer> functionCalls;

Pattern pattern_diff = Pattern.compile("diff\\s--git\\sa/(.*)\\sb/(.*)"); // pattern for the lines begining with "diff"
Pattern pattern_region = Pattern.compile("^(@@\\s-[0-9]*\\,[0-9]*\\s\\+[0-9]*\\,[0-9]*\\s@@)"); // pattern for the region starters
Pattern pattern_function = Pattern.compile ("(?<!(def))\\s([\\w][\\w\\.]*)\\([\\w,\\s]*\\)"); // pattern for function calls not preceded by "def"
Pattern pattern_function_define = Pattern.compile ("(?<=(#define)).*\\s([\\w][\\w\\.]*)\\([\\w,\\s]*\\)"); // pattern for function calls preceded by "#define"
Pattern pattern_function_com = Pattern.compile ("(?<=(/\\*)).*\\s([\\w][\\w\\.]*)\\([\\w,\\s]*\\)"); // pattern for function calls preceded by "/*" (comment)

boolean in_region = false; // boolean used to see if we are in a region while parsing a file

public DiffResult() {
this.files = new ArrayList<String>();
this.functionCalls = new HashMap<String, Integer>();
}
//String returns the value of results as a formated string
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Files: \n");

for( String file : files){
buffer.append(" -");
buffer.append(file);
buffer.append("\n");
}

this.appendIntValueToBuffer(this.regions, "Regions", buffer);
this.appendIntValueToBuffer(this.lineAdded, "LA", buffer);
this.appendIntValueToBuffer(this.lineDeleted, "LD", buffer);

buffer.append("Functions calls: \n");

for(String key : this.functionCalls.keySet()) {
this.appendIntValueToBuffer(functionCalls.get(key), key, buffer);
}

return buffer.toString();
}

//appendIntValueToBuffer appends int value to a bytes buffer
public void appendIntValueToBuffer(int value, String label, StringBuffer buffer) {
buffer.append(label);
buffer.append(" : ");
buffer.append(value);
buffer.append("\n");
}

public void parseFile(String filename) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(filename));
String line;
while((line = br.readLine()) != null) { // for each line in the current file

matchDiffLine(line);
matchRegions(line);
matchLineMod(line);
matchFunctionCall(line);
}
}
catch(IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
finally {
try {
if (br != null) {
br.close();
}
}
catch(IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
this.in_region = false; // end if fuke
}

public void matchDiffLine(String line) {
Matcher m_diff = pattern_diff.matcher(line); // matcher for the line starting with "diff"

if (m_diff.find()) { // find files

String file = m_diff.group(1); // filename of the file on which the diff is done
if(!this.files.contains(file)){ // ignore files already in the list
this.files.add(file);
}

file = m_diff.group(2); // filename of the file on which the diff is done
if(!this.files.contains(file)){ // ignore files already in the list
this.files.add(file);
}

this.in_region = false; // if the diff call is called, we are not in a region
}
}

public void matchRegions(String line) {
// Count regions
Matcher m_regions = pattern_region.matcher(line); // matcher for region starters
if (m_regions.find()) {
this.regions++;

this.in_region = true;
}
}

public void matchLineMod(String line) {
// Count number of line added
if(this.in_region && line.charAt(0) == '+') { // check that we are in a region
this.lineAdded++;
}

// Count number of line deleted
if(this.in_region && line.charAt(0) == '-') { // check that we are in a region
this.lineDeleted++;
}
}

public void matchFunctionCall(String line) {
// Functions calls
// for this part I was not sure what was asked so I counted the function
// calls added minus function calls removed to give the net augmentation.
// Using this computation, the number might me zero.
if(this.in_region) {
Matcher m_funct = pattern_function.matcher(line);

// find functions not preceded by "def", "#define" are "/*"
// This way of identifying the function calls is fits the current
// diff files but might need improvement to cover more cases.
if (m_funct.find() && ! (pattern_function_define.matcher(line).find() || pattern_function_com.matcher(line).find()) ) {

String funct = m_funct.group(m_funct.groupCount()); // find the function name

int loc = 0;
if(this.functionCalls.containsKey(funct)) {
loc = this.functionCalls.get(funct); // count of that function if already in map
}

/* VERSION 1 : counts all calls, even replicates */
this.functionCalls.put(funct, loc +1);

/* VERSION 2 : counts added calls minus removed calls */
// if(line.charAt(0) == '+') {
// this.functionCalls.put(funct, loc +1);
// }
// else if(line.charAt(0) == '-') {
// this.functionCalls.put(funct, loc -1);
// }
// // will only count the function added in a added line (preceded by "+")
// // or remove 1 if the function was in a removed line (preceded by "-")

/* VERSION 3 : counts calls in lines not preceded by "-" (removed lines) */
// if(line.charAt(0) != '-') {
// this.functionCalls.put(funct, loc +1);
// }
}
}
}
}
100 changes: 100 additions & 0 deletions Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import java.io.File;

import java.lang.StringBuffer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Iterator;

import org.json.*;

public class Main {

//main is the entry point of our go program. It defers
//the execution of timeTrack so we can know how long it
//took for the main to complete.
//It also calls the compute and output the returned struct
//to stdout.
public static void main(String[] args) {
computeTime(System.currentTimeMillis(), computeDiff().toString(), "compute diff");
computeTime(System.currentTimeMillis(), computeAST().toString(), "compute AST");
}

public static void computeTime(long StartTime, String s, String text) {
long EndTime = System.currentTimeMillis();
System.out.println(s);
System.out.println(String.format("%s took %d ms", text, EndTime - StartTime));

}

//compute parses the git diffs in ./diffs and returns
//a diffResult struct that contains all the relevant informations
//about these diffs
// list of files in the diffs
// number of regions
// number of line added
// number of line deleted
// list of function calls seen in the diffs and their number of calls
public static DiffResult computeDiff() {
DiffResult diff = new DiffResult();

String PATH = "./diffs/";
File folder = new File(PATH);
File[] listOfFiles = folder.listFiles();

for (int i = 0; i < listOfFiles.length ; i++) { // for each diff in the folder "diffs"
String filename = PATH + listOfFiles[i].getName();

diff.parseFile(filename);
}

return diff;
}

//computeAST go through the AST and returns
//a astResult struct that contains all the variable declarations
public static AstResult computeAST() {
AstResult AST = new AstResult();

BufferedReader br = null;
StringBuffer bs = new StringBuffer();

String filename = "ast/astChallenge.json";
try {
br = new BufferedReader(new FileReader(filename));
String line;

while((line = br.readLine()) != null) { // read all the lines of the file
bs.append(line);
}

JSONObject jo = new JSONObject(bs.toString()); // create a JSONObject from the text in the file

AST.propagate(jo.getJSONObject("Root")); // travels through the JSONObject through the Children (see function below)
}
catch(IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
catch(JSONException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
finally {
try {
if (br != null) {
br.close();
}
}
catch(IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
return AST;
}
}
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
all: compile do_main

compile:
javac -classpath ./:java-json.jar *.java


do_main:
java -cp ./:java-json.jar Main > out.txt

clear:
rm *.class
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# Notes from Doriane Olewicki

Here is my implementation of the two challenges. I implemented it in Java and provided a Makefile to run my code. This Makefile will work on MacOS but I have not tested it on a Linux are Windows environment.

I left the golang files but they are not modified.

In the out.txt file, you can find my output results.

# Clever Initiative Challenge

The Clever-Initiative is a team of the Technology Group @ Ubisoft Montreal. Our goal is to discover, improve and promote state-of-the-art software engineering practices that aim to ease the production of quality. By augmenting the quality of our products, we mechanically improve the productivity of our teams as they can focus creating features rather than fixing bugs.
Expand Down
Binary file added java-json.jar
Binary file not shown.
Loading