# Why code reviews are good, but not enough

Code reviews are definitely necessary and useful. It’s a way to impart knowledge, educate, control a task, improve code quality and formatting, fix bugs. Moreover, you can notice high-level errors related to the architecture and algorithms used. So it’s a must-have practice, except that people get tired quickly. Therefore, static analysis perfectly complements reviews and helps to detect a variety of inconspicuous errors and typos. Let’s look at a decent example on this topic.

Try to find an error in the code of a function taken from the structopt library:

staticinlineboolis_valid_number(conststd::string &input) {

if(is_binary_notation(input) ||

is_hex_notation(input) ||

is_octal_notation(input)) {

returntrue;

}if(input.empty()) {

returnfalse;

} std::size_ti = 0, j = input.length() - 1;// Handling whitespaces

while(i < input.length() && input[i] == ' ')

i++;

while(input[j] == ' ')

j--;if(i > j)

returnfalse;// if string is of length 1 and the only

// character is not a digit

if(i == j && !(input[i] >= '0' && input[i] <= '9'))

returnfalse;// If the 1st char is not '+', '-', '.' or digit

if(input[i] != '.' && input[i] != '+' && input[i] != '-' &&

!(input[i] >= '0' && input[i] <= '9'))

returnfalse;// To check if a '.' or 'e' is found in given

// string. We use this flag to make sure that

// either of them appear only once.

booldot_or_exp = false;for(; i <= j; i++) {

// If any of the char does not belong to

// {digit, +, -, ., e}

if(input[i] != 'e' && input[i] != '.' &&

input[i] != '+' && input[i] != '-' &&

!(input[i] >= '0' && input[i] <= '9'))

returnfalse;if(input[i] == '.') {

// checks if the char 'e' has already

// occurred before '.' If yes, return false;.

if(dot_or_exp == true)

returnfalse;// If '.' is the last character.

if(i + 1 > input.length())

returnfalse;// if '.' is not followed by a digit.

if(!(input[i + 1] >= '0' && input[i + 1] <= '9'))

returnfalse;

}elseif(input[i] == 'e') {

// set dot_or_exp = 1 when e is encountered.

dot_or_exp = true;// if there is no digit before 'e'.

if(!(input[i - 1] >= '0' && input[i - 1] <= '9'))

returnfalse;// If 'e' is the last Character

if(i + 1 > input.length())

returnfalse;// if e is not followed either by

// '+', '-' or a digit

if(input[i + 1] != '+' && input[i + 1] != '-' &&

(input[i + 1] >= '0' && input[i] <= '9'))

returnfalse;

}

}/* If the string skips all above cases, then

it is numeric*/

returntrue;

}

To avoid accidentally reading the answer right away, I’ll add a picture.

I don’t know if you found the error or not. Even if you found it, I’m sure you’ll agree that it’s not easy to find such a typo. Moreover, you knew that there was an error in the function. If you hadn’t known, it would have been hard to make you read and check all this code carefully.

In such cases, a static code analyzer will perfectly complement the classic code review. The analyzer doesn’t get tired and will thoroughly check all the code. As a result, the PVS-Studio analyzer notices an anomaly in this function and issues a warning:

V560 A part of conditional expression is always false: input[i] <= ‘9’. structopt.hpp 1870

For those who didn’t notice the error, I will give an explanation. Here’s the main part:

**else** **if** (input[i] == 'e') {

....

**if** (input[i + 1] != '+' && input[i + 1] != '-' &&

(input[i + 1] >= '0' && input[i] <= '9'))

**return** false;

}

The above condition checks that the i-th element is the letter ‘e’. Accordingly, the following check *input[i] <= ‘9’* doesn’t make sense. The result of the second check is always *false*, which is what the static analysis tool warns you about. The reason for the error is simple: the person was hasty and made a typo, forgetting to write +1.

In fact, it turns out that the function doesn’t check the correctness of the entered numbers as expected. Correct version:

**else** **if** (input[i] == 'e') {

....

**if** (input[i + 1] != '+' && input[i + 1] != '-' &&

(input[i + 1] >= '0' && input[i + 1] <= '9'))

**return** false;

}

**Here’s an interesting fact.** This error can be considered as a kind of the “last line effect” one. An error was made in the last condition of the function. By the end of this snippet, the programmer’s attention weakened, and they made this barely noticeable mistake.

If you like the article about the last line effect, I recommend reading about other similar ideas: 0–1–2, memset, comparisons.

Bye everyone. Kudos to those who found the bug themselves.