top of page

Music

Music

Screenshots

Developer uses copy-paste-modify to extend functionalities. He annotates the copy pasted methods with #pragma ast as shown above. He invokes the Copy Paste Merge refactoring. NOTE: The input file for the prototype version must be called input.cpp and be inside a project called astdifftest

The merged method is called "mergedFunction". The earlier methods are all replaced with a call to the mergedMethod with parameters updated based on the abstraction pattern being used. 

Description

The Clonerge is an eclipse plugin that runs on top of Eclipse CDT. The prototype version of the tool identifies "merge points" based on the approach specified in the paper "Copy Paste Redeemed" by me, Krishna Narasimhan and my Supervisor, Dr. Christoph Reichenbach. This paper is due to appear in the main track of ASE 2015. For each of the merge points, the clonerge tool, performs an abstraction as follows:

 

  1. For merge points that involve constants, an extra parameter is added.  (See the screenshots)

  2. For merge points that involve types, an extra template type is added.

  3. For merge points  that involve field expressions, an extra parameter is added and pointers are handled if the field expressions are LValues

  4. For merge points that involve differences at the Statement level, a Switch statement is constructed to branch between diffferent functions and the function name is supplied as an extra parameter.

 

The prototype version expects:

  1. That the input be called input.cpp

  2. That the input be placed in the root folder of a project called astdifftest

  3. The copy pasted methods be preceeded with the annotation #pragma ast (astno) where astno indicates the index of the method. The developer can simply use number indexes starting with 1 to mark the code he believes is copy pasted.

Download

The version of Eclipse (for Windows) with the refactoring installed as a plugin can be downloaded here :

 

https://www.dropbox.com/l/EqsUNLh6oQagDo7HmDVcir

 

 

A 6 minute video demonstrating the use of the tool:

 

http://youtu.be/vm8s0-TM0tY?hd=1

 

Steps to test:

1. Extract the Eclipse rar file, open the executable, and specify a folder for the workspace.

2. Create a C++ project called "astdifftest" . Select New-> Other -> C++ project. Just provide the name as astdifftest and click next for all other wizard pages. 

3. Be sure to change the perspective to C++. Because the Copy paste merge refactoring is available only in this perspective.

4. Create a new file inside the "astdifftest" project and call it "input.cpp"

5. Copy the following code into input.cpp. These are real clone groups from the open source repositories that were evaluated as part of the research. For more info, read the ASE main track paper. Each of the sections titled Group1, Group2 are each clone group. Be careful to remove the comments from only one set of pragmas. Otherwise, the tool may get confused. After you have uncommented one group's pragma statements, use the Copy Paste Merge refactoring option to see the result in a new file in the same project.

 

 

 

//=============Group 1===========================================

//#pragma ast 1

Handle<Value> Connection::GetModule (Local<String> property,

                                     const AccessorInfo& info)

{

  HandleScope scope;

  Connection* njsConn = ObjectWrap::Unwrap<Connection>(info.Holder());

  if(!njsConn->isValid_)

    msg = NJSMessages::getErrorMsg(errInvalidConnection);

  else

    msg = NJSMessages::getErrorMsg(errWriteOnly, "module1");

  NJS_SET_EXCEPTION(msg.c_str(), (int) msg.length());

  return Undefined();

}

 

//#pragma ast 2

Handle<Value> Connection::GetClientId(Local<String> property,

                                      const AccessorInfo& info)

{

  HandleScope scope;

  Connection* njsConn = ObjectWrap::Unwrap<Connection>(info.Holder());

  if(!njsConn->isValid_)

    msg = NJSMessages::getErrorMsg(errInvalidConnection);

  else

    msg = NJSMessages::getErrorMsg(errWriteOnly, "clientId");

  NJS_SET_EXCEPTION(msg.c_str(), (int) msg.length());

  return Undefined();

}

 

//#pragma ast 3

Handle<Value> Connection::GetAction(Local<String> property,

                                      const AccessorInfo& info)

{

  HandleScope scope;

  Connection* njsConn = ObjectWrap::Unwrap<Connection>(info.Holder());

  if(!njsConn->isValid_)

    msg = NJSMessages::getErrorMsg(errInvalidConnection);

  else

    msg = NJSMessages::getErrorMsg(errWriteOnly, "action");

  NJS_SET_EXCEPTION(msg.c_str(), (int) msg.length());

  return Undefined();

}

 

 

//=============Group 2===========================================

//#pragma ast 1

cJSON *cJSON_CreateIntArray(int *numbers) {

    cJSON *n=0,*p=0,*a=cJSON_CreateArray();

    for (int i=0;a && i<count;i++) {

        n=cJSON_CreateNumber(numbers[i]);

        if(!i) {

            a->head=n;

        } else {

            suffix_object(p,n);

        }

        p=n;

    }

    a->tail = p;

    return a;

}

 

//#pragma ast 2

cJSON *cJSON_CreateDoubleArray(double *numbers) {

    cJSON *n=0,*p=0,*a=cJSON_CreateArray();

    for (int i=0;a && i<count;i++) {

        n=cJSON_CreateNumber(numbers[i]);

        if(!i) {

            a->head=n;

        } else {

            suffix_object(p,n);

        }

        p=n;

    }

    a->tail = p;

    return a;

}

 

 

//=============Group 3===========================================

//#pragma ast 1

void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const {

  // Print the service.

fn1();

float x = 10;

}

 

 

//#pragma ast 2

void Generator::PrintServiceStub(const ServiceDescriptor& descriptor) const {

  // Print the service stub.

  fn2();

  float x = 10;

}

 

//=============Group 4===========================================

//#pragma ast 1

Type typeDiv(Type t1, Type t2) {

  if (auto t = eval_const_divmod(t1, t2, cellDiv)) return *t;

  x = 10;

  return TInitPrim;

}

 

//#pragma ast 2

Type typeMod(Type t1, Type t2) {

  if (auto t = eval_const_divmod(t1, t2, cellMod)) return *t;

  y = 10;

  return TInitPrim;

}

 

 

//=============Group 5===========================================

//#pragma ast 1

bool Camera3DTestDemo::onTouchesZoomOut(Touch* touch, Event* event)

{

    auto target = static_cast<Label*>(event->getCurrentTarget());

 

    Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());

    Size s = target->getContentSize();

    Rect rect = Rect(0, 0, s.width, s.height);

 

    if (rect.containsPoint(locationInNode))

    {

        _bZoomOut = true;

        return true;

    }

    return false;

}

 

//#pragma ast 2

bool Camera3DTestDemo::onTouchesZoomIn(Touch* touch, Event* event)

{

    auto target = static_cast<Label*>(event->getCurrentTarget());

 

    Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());

    Size s = target->getContentSize();

    Rect rect = Rect(0, 0, s.width, s.height);

 

    if (rect.containsPoint(locationInNode))

    {

        _bZoomIn = true;

        return true;

    }

    return false;

}

 

//#pragma ast 3

bool Camera3DTestDemo::onTouchesRotateLeft(Touch* touch, Event* event)

{

    auto target = static_cast<Label*>(event->getCurrentTarget());

 

    Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());

    Size s = target->getContentSize();

    Rect rect = Rect(0, 0, s.width, s.height);

 

    if (rect.containsPoint(locationInNode))

    {

        _bRotateLeft = true;

        return true;

    }

    return false;

}

 

//#pragma ast 4

bool Camera3DTestDemo::onTouchesRotateRight(Touch* touch, Event* event)

{

    auto target = static_cast<Label*>(event->getCurrentTarget());

 

    Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());

    Size s = target->getContentSize();

    Rect rect = Rect(0, 0, s.width, s.height);

 

    if (rect.containsPoint(locationInNode))

    {

        _bRotateRight = true;

        return true;

    }

    return false;

}

 

 

bottom of page