Code Refactoring

Klocwork Code Refactoring provides a mechanism to simplify and clarify code without changing the program’s behaviour; the beginning and end products are functionally identical. Refactoring makes code:

  • easier to maintain and re-use
  • simpler to understand
  • cheaper to change

You can:

  • rename entities whose scope is file-local, in order to make your identifier names more meaningful.
  • extract methods or functions (with duplicate detection in Eclipse and Visual Studio) from large and unwieldy methods to create smaller and more logical functions. The newly extracted function is added to your source file, while the selected code is replaced with a call to that function.
  • introduce variables (with duplicate detection in Eclipse and Visual Studio) to simplify complicated expressions. Occurrences of the expression are replaced with the new variable(s).
  • inline variables, replacing all occurrences of a given variable with its initial value; this is the opposite of introducing variables.
  • inline functions to remove the overhead of an overly segmented source layout. Typical candidates for inlining are simple functions that are called from few locations, but which might be invoked frequently at runtime, such as from an inner loop. These are functions that might best benefit from the overhead of function calling being removed. Inlining functions involves placing the method’s body into the body of its caller(s) and removing the method.
  • analyze headers, reporting missing transitive includes and unnecessary includes.
  • optimize headers, applying any unused header and missing transitive header changes all in one step, without user confirmation.

Rename

To make identifier names more meaningful, rename a variable or function. You can rename:

  • local variables
  • function parameters
  • static functions and variables

The new name is checked against existing code to prevent hiding names of existing variables, functions, types, or namespaces, as well as naming conflicts.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
int boo(int b) {
}

int bar(int (*func)(char*)) {        
    return 1;
}
 
void foo(int a) {
    int i = 2;
    i = 3;
    a = 567;
    a = boo(a);
}

In the above snippet, b, func, a and i can all be renamed as specified.

Extract Function

When you use the Extract Function option, a new function is created, and the selected code is inserted as the body of the function. The selected code must be a syntactically complete, non-empty sequence of complete statements and/or expressions.

Implementation notes

  • The selected code fragment is replaced with a call to a new function, and any variables that are used inside the code fragment are passed to a new function as input or output parameters.
  • A new function with only one output parameter of a primitive type (such as pointer, char, bool, or int) is automatically converted into a function, returning a value of this type and no output parameters.
  • For C output, parameters are declared as pointers to the original type.
  • For C++ output, parameters are declared as references to the original type. If the current function is a member function of a C++ class, a declaration of the new function is inserted into the class definition as a protected member.
  • The original indentation and whitespace are preserved where possible
  • Comments, macros and preprocessor directives within your selection are preserved during this code transformation. This example code shows some code selected for refactoring:
1
2
3
4
5
6
7
8
9
10
11
12
int foo() {
    int a;

    /* selection starts -> */
    #define MY_MACRO 1
 
    a = MY_MACRO;
    /* <- selection ends */

    a = a + 20;
    return a;
}

You can see that the ‘define’ directive is preserved in the extracted function:

1
2
3
4
5
6
7
8
int extracted_function()
{
    int a;
    #define MY_MACRO 1
    a = MY_MACRO;

    return a;
}

Limitations

  • The selected code fragment can’t contain jump statements (“goto”), but return statements will work.
  • The selected code fragment can’t contain label statements, but switch statements (with labels) will work.
  • Extraction from template functions is not supported.

Example

1
2
3
4
5
6
int main() {         
    int a;                 
    a++;           
 
    return a;
}

Here, ‘a++’ can be extracted into ‘new_function’.

Result

1
2
3
4
5
6
7
8
9
10
void new_function(int *a) {  
    (*a)++;
}

int main() {
    int a;
    new_function(&a);
   
    return a;
}

Introduce Variable

Introduce Variable allows you to quickly create a new local variable from the selected expression, initialize it with the expression, and replace all occurrences of the expression in the code with references to the newly introduced variable. The opposite action is to refactor by inlining a variable, which replaces the variable with its initial expression.

Implementation notes

  • The declaration of the new local variable, initialized with the selected expression, is inserted into the current statement. The selected expression is replaced with the name of the new variable.
  • The new name is checked against existing code to prevent hiding names of existing variables, functions, types, or namespaces, as well as naming conflicts.
  • For C++, the declaration and initializer of the new variable are merged into a single statement and inserted directly before the selected statement.
  • For C, the declaration and initializer may have to be split. The declaration is inserted at the beginning of the current block or function, and the initializing assignment is inserted directly before the selected statement.

Example

The highlighted text in the snippet below can be replaced with a variable:

1
2
3
4
5
6
7
int main() {               
    int c;         
         
    c = 1 + 2 + 3 + 4 + 5;
             
    return c;                    
}

Result

1
2
3
4
5
6
7
8
9
int main() {
    int temp;
    int c;

    temp = 2 + 3 + 4 + 5;
    c = 1 + temp;  
                                 
    return c;
}

Inline Variable

Inline Variable allows you to replace all occurrences of a given variable with its initial value. The opposite action is to refactor by introducing a variable.

Example

The highlighted variable can be replaced by an expression:

1
2
3
4
5
6
7
8
int main() {
    int temp;
    int c;

    temp = 2 + 3 + 4 + 5;
    c = 1 + temp;                                    
    return c;
}

Result

1
2
3
4
5
6
7
int main() {               
    int c;  
                 
    c = 1 + 2 + 3 + 4 + 5; 
         
    return c;                    
}

Inline Function

When you inline a function, the complete body of a function is inserted for each occurrence of the selected function.

Implementation notes

  • When you select the definition of a function, the function is removed from the source file, and every call to this function is replaced with the function body.
  • When you select a call to a function, only this call is inlined, and the function definition is left unchanged.
  • The parameters and local variables of a function are renamed during substitution.

Limitations

  • Only inline and static functions are supported.
  • You can’t inline:
    • recursive functions
    • functions with more than one return statement
    • functions referenced by address

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
static int foo(int a) {          
    int b = a + 2; 
               
    return b;                    
}
                         
int main() {                     
    int c; 
                     
    c = foo(1);
             
    return c;
}

In this example, we can inline ‘foo’.

Result

1
2
3
4
5
6
7
8
9
int main() {
    int c;
    int a = 1;  
    int b = a + 2;
 
    c = b;
 
    return c;
}

Can’t inline function declared in system header

You’ll see this message if the function definition is found in the system header.

For example, this message will occur if there’s an attempt to inline ‘pow’ from ‘math.h’ in the snippet below:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <stdio.h>
#include <math.h>
 
using namespace std;
 
#define PI 3.14
 
static float getArea(float radius) {
    float area = PI * *pow(radius, 2)*;
    return area;
}

Can’t inline function: This function is invoked using its fully qualified name

You can inline a function if it is called directly from another class member, but you’ll trigger this message if you attempt to inline functions such as ‘x->foo()’ or ‘x.foo()’ in the situations noted below:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A{
    void foo() {...}
    void abc();
}

void A::abc()
{
    foo();            // We can inline this
 
    A::foo();         // We can't inline this
    A x = new A();
    x->foo();         // We can't inline this
}

About Rogue Wave Software

Rogue Wave Software are the largest independent provider of cross-platform software development tools and embedded components in the world. Through decades of solving the most complex problems across financial services, telecommunications, healthcare, government, academia, and other industries, Rogue Wave tools, libraries, and services enable developers to write better code, faster. More details…

Find out more…

For more information on Klocwork static analysis, code refactoring or a 7-day free trial, please complete the form below.

Full Name (required):

Company Name (required):

Your Email (required)