Replaced regex for matching multi-line function calls

Instead use a more complex system that finds the matching closing
bracket and checks all the lines in between to check one parameter only
on each line.

It handles nested function calls by skipping over their whole parameter
list (since we don't require nested functions be separated onto
individual lines just because the outer call is. Instead these get
checked when we get to this function call separately.
This commit is contained in:
thk123 2017-01-09 17:55:26 +00:00
parent ddea7158ed
commit eb4597d04a
8 changed files with 297 additions and 3 deletions

View File

@ -11,6 +11,8 @@ Whitespaces:
- For brackets, break after the bracket
- In the case of function calls, put each argument on a separate line if
they do not fit after one line break
- Nested function calls do not need to be broken up into separate lines even
if the outer function call does.
- If a method is bigger than 50 lines, break it into parts.
- Put matching { } into the same column.
- No spaces around operators (=, +, ==, ...)

View File

@ -0,0 +1,79 @@
/*******************************************************************\
Module: Lint Examples
Author: Thomas Kiley, thomas@diffblue.com
\*******************************************************************/
/*******************************************************************\
Function: fun
Inputs:
Outputs:
Purpose:
\*******************************************************************/
static void fun()
{
// Correct
foo(
x,
y);
// Incorrect, x should be on the next line
foo(x,
y);
// Incorrect indent should be only 2
foo(
x,
y);
// Correct
int x=bar(
x,
y);
// Incorrect, x should be on the next line
int x=bar(x,
y);
// Incorrect indent should be only 2
int x=bar(
x,
y);
// Correct
*model=baz(
x,
y);
// Incorrect, x should be on the next line
*model=baz(x,
y);
// Incorrect indent should be only 2
*model=baz(
x,
y);
// Correct
var->fun(
x,
y);
// Incorrect, x should be on the next line
var->fun(x,
y);
// Incorrect indent should be only 2
var->fun(
x,
y);
}

View File

@ -0,0 +1,15 @@
CORE
main.cpp
^main\.cpp:29: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^main\.cpp:34: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
^main\.cpp:43: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^main\.cpp:48: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
^main\.cpp:57: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^main\.cpp:62: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
^main\.cpp:71: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^main\.cpp:76: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
^Total errors found: 8$
^EXIT=1$
^SIGNAL=0$
--

View File

@ -0,0 +1,67 @@
/*******************************************************************\
Module: Lint Examples
Author: Thomas Kiley, thomas@diffblue.com
\*******************************************************************/
/*******************************************************************\
Function: fun
Inputs:
Outputs:
Purpose:
\*******************************************************************/
static void fun()
{
// Incorrect, call should be on a new line
nested(call(),
another_param);
// Incorrect - should be indented by 2
nested(
call(),
another_param);
// Correct
nested(
call(),
another_param);
// Correct
twice(
nested(
call(
param1),
param2),
param3)
// Correct
foo(
bar(x, y),
z);
// Correct
foo(
bar(
x,
y),
z);
// Incorrect, the bar arguments have been split up therefore
// they all should be split up
foo(
bar(x,
y),
z);
// Incorrect bar should be on the next line
foo(bar(x, y),
z);
}

View File

@ -0,0 +1,11 @@
CORE
main.cpp
^main\.cpp:24: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^main\.cpp:29: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
^main\.cpp:60: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^main\.cpp:65: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
^Total errors found: 4$
^EXIT=1$
^SIGNAL=0$
--

View File

@ -0,0 +1,47 @@
/*******************************************************************\
Module: Lint Examples
Author: Thomas Kiley, thomas@diffblue.com
\*******************************************************************/
/*******************************************************************\
Function: fun
Inputs:
Outputs:
Purpose:
\*******************************************************************/
static void fun()
{
// Correct as for loop not function
for(int x=0;
x<10;
++x)
{}
// Correct as an if statement not a function
if(a==b ||
c==d)
{
do_something();
}
// Correct as ranged based for loop not function
for(x:
list)
{}
// Correct since if statement
if(some_check(with, params)==
some_value)
{
do_something();
}
}

View File

@ -0,0 +1,7 @@
CORE
main.cpp
^Total errors found: 0$
^EXIT=0$
^SIGNAL=0$
--

72
scripts/cpplint.py vendored
View File

@ -4686,9 +4686,75 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
if linenum>0:
while prev_initial_spaces < len(prev) and prev[prev_initial_spaces] == ' ':
prev_initial_spaces += 1
if Search(r'\([^\)]*,$', elided_line) or Search(r'\(\[^\)]*, $', elided_line):
error(filename, linenum, 'whitespace/indent', 4,
'If parameters or arguments require a line break, each parameter should be put on its own line.')
# here a regex isn't sufficent we need a stack to match brackets
# because even an open bracket and a , at the end might just be function call
# as a parameter.
# Instead the rule we try to apply here is:
# - if we find an opening bracket, we find the matching closing bracket
# - if the bracket is on a different line we require all of the parameters to be on a separate line
# - if there is another opening bracket Skip to the closing bracket as will be checked in a subsequent line check
# - ignore the line if it is a for/if etc since rules are different
# Look for an opening bracket that doesn't have a semi-colon on the same line
bracket_search = Search(r'(?P<bracket>\()[^;]*,[^;]*$', elided_line)
# Exclude the check if any of these keywords are present
# They could trip us up as they have different formatting rules to functions
keyword_search = Search(r'\b(if|for|while|catch|switch)\b', elided_line)
if bracket_search and not keyword_search:
open_bracket_pos = bracket_search.start('bracket')
close_line, close_linenum, close_pos = CloseExpression(clean_lines, linenum, open_bracket_pos)
if close_pos != -1:
# If the closing line is different from the opening line we need to
# verify that each of the parameters are on separate lines
if close_linenum != linenum:
# The first line needs to have no parameters on it
if(Search(r'\(.+', elided_line)):
error(filename, linenum, 'whitespace/indent', 4,
'If parameters or arguments require a line break, each parameter should be put on its own line.')
# For each line afer we need to verify it consists of exactly one parameter
# Except if we find an opening bracket - in this case we ignore everything until the closing
# bracket (any errors within these brackets will be picked up when we check this line)
start_linenum = linenum + 1
while(start_linenum < close_linenum):
arg_line = clean_lines.elided[start_linenum]
nested_bracket_search = Search('\(', arg_line)
if nested_bracket_search:
nested_open_bracket_pos = nested_bracket_search.start()
# Just because we are calling a nested function doesn't mean
# we allow multiple parameters on the line
if(Search(',', arg_line[:nested_open_bracket_pos])):
error(filename, start_linenum, 'whitespace/indent', 4,
'If parameters or arguments require a line break, each parameter should be put on its own line.')
nested_close_line, nested_close_linenum, _ = CloseExpression(clean_lines, start_linenum, nested_open_bracket_pos)
# If anything other closing statements or commas appear there is another parameter after the nested call
if not Search(r'\)(,|\)|;)*', nested_close_line):
error(filename, start_linenum, 'whitespace/indent', 4,
'If parameters or arguments require a line break, each parameter should be put on its own line.')
# Skip to the end of the bracket
start_linenum = nested_close_linenum
start_linenum+=1
# For the final line we also need to check one parameter on it
# e.g. we require bracket on same line as last parameter
# foo(
# x);
if not Search(r'^\s*[^,]+\)', close_line):
# If this is true, the we failed because we just had the close bracket
if Search(r'[^,]*\)', close_line):
error(filename, close_linenum, 'whitespace/indent', 4,
'If parameters or arguments require a line break, the closing bracket should be on the same line as the final parameter')
else:
# In this case the problem is we had a bracket
# i.e. more than one parameter on the last line
error(filename, close_linenum, 'whitespace/indent', 4,
'If parameters or arguments require a line break, each parameter should be put on its own line.')
if (Search(r'\([^\)]*$', elided_prev) and initial_spaces-2 != prev_initial_spaces) and not Search(r'for|while|if|;', elided_prev):
error(filename, linenum, 'whitespace/indent', 4,
'Indent of wrapped parenthesized expression or parameter or argument list should be 2')