Skip to content

Commit eb4597d

Browse files
author
thk123
committed
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.
1 parent ddea715 commit eb4597d

File tree

8 files changed

+297
-3
lines changed

8 files changed

+297
-3
lines changed

CODING_STANDARD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Whitespaces:
1111
- For brackets, break after the bracket
1212
- In the case of function calls, put each argument on a separate line if
1313
they do not fit after one line break
14+
- Nested function calls do not need to be broken up into separate lines even
15+
if the outer function call does.
1416
- If a method is bigger than 50 lines, break it into parts.
1517
- Put matching { } into the same column.
1618
- No spaces around operators (=, +, ==, ...)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*******************************************************************\
2+
3+
Module: Lint Examples
4+
5+
Author: Thomas Kiley, thomas@diffblue.com
6+
7+
\*******************************************************************/
8+
9+
/*******************************************************************\
10+
11+
Function: fun
12+
13+
Inputs:
14+
15+
Outputs:
16+
17+
Purpose:
18+
19+
\*******************************************************************/
20+
21+
static void fun()
22+
{
23+
// Correct
24+
foo(
25+
x,
26+
y);
27+
28+
// Incorrect, x should be on the next line
29+
foo(x,
30+
y);
31+
32+
// Incorrect indent should be only 2
33+
foo(
34+
x,
35+
y);
36+
37+
// Correct
38+
int x=bar(
39+
x,
40+
y);
41+
42+
// Incorrect, x should be on the next line
43+
int x=bar(x,
44+
y);
45+
46+
// Incorrect indent should be only 2
47+
int x=bar(
48+
x,
49+
y);
50+
51+
// Correct
52+
*model=baz(
53+
x,
54+
y);
55+
56+
// Incorrect, x should be on the next line
57+
*model=baz(x,
58+
y);
59+
60+
// Incorrect indent should be only 2
61+
*model=baz(
62+
x,
63+
y);
64+
65+
// Correct
66+
var->fun(
67+
x,
68+
y);
69+
70+
// Incorrect, x should be on the next line
71+
var->fun(x,
72+
y);
73+
74+
// Incorrect indent should be only 2
75+
var->fun(
76+
x,
77+
y);
78+
}
79+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
main.cpp
3+
4+
^main\.cpp:29: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
5+
^main\.cpp:34: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
6+
^main\.cpp:43: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
7+
^main\.cpp:48: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
8+
^main\.cpp:57: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
9+
^main\.cpp:62: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
10+
^main\.cpp:71: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
11+
^main\.cpp:76: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
12+
^Total errors found: 8$
13+
^EXIT=1$
14+
^SIGNAL=0$
15+
--
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*******************************************************************\
2+
3+
Module: Lint Examples
4+
5+
Author: Thomas Kiley, thomas@diffblue.com
6+
7+
\*******************************************************************/
8+
9+
/*******************************************************************\
10+
11+
Function: fun
12+
13+
Inputs:
14+
15+
Outputs:
16+
17+
Purpose:
18+
19+
\*******************************************************************/
20+
21+
static void fun()
22+
{
23+
// Incorrect, call should be on a new line
24+
nested(call(),
25+
another_param);
26+
27+
// Incorrect - should be indented by 2
28+
nested(
29+
call(),
30+
another_param);
31+
32+
// Correct
33+
nested(
34+
call(),
35+
another_param);
36+
37+
// Correct
38+
twice(
39+
nested(
40+
call(
41+
param1),
42+
param2),
43+
param3)
44+
45+
// Correct
46+
foo(
47+
bar(x, y),
48+
z);
49+
50+
// Correct
51+
foo(
52+
bar(
53+
x,
54+
y),
55+
z);
56+
57+
// Incorrect, the bar arguments have been split up therefore
58+
// they all should be split up
59+
foo(
60+
bar(x,
61+
y),
62+
z);
63+
64+
// Incorrect bar should be on the next line
65+
foo(bar(x, y),
66+
z);
67+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.cpp
3+
4+
^main\.cpp:24: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
5+
^main\.cpp:29: Indent of wrapped parenthesized expression or parameter or argument list should be 2 \[whitespace/indent\] \[4\]
6+
^main\.cpp:60: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
7+
^main\.cpp:65: If parameters or arguments require a line break, each parameter should be put on its own line\. \[whitespace/indent\] \[4\]
8+
^Total errors found: 4$
9+
^EXIT=1$
10+
^SIGNAL=0$
11+
--
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*******************************************************************\
2+
3+
Module: Lint Examples
4+
5+
Author: Thomas Kiley, thomas@diffblue.com
6+
7+
\*******************************************************************/
8+
9+
/*******************************************************************\
10+
11+
Function: fun
12+
13+
Inputs:
14+
15+
Outputs:
16+
17+
Purpose:
18+
19+
\*******************************************************************/
20+
21+
static void fun()
22+
{
23+
// Correct as for loop not function
24+
for(int x=0;
25+
x<10;
26+
++x)
27+
{}
28+
29+
// Correct as an if statement not a function
30+
if(a==b ||
31+
c==d)
32+
{
33+
do_something();
34+
}
35+
36+
// Correct as ranged based for loop not function
37+
for(x:
38+
list)
39+
{}
40+
41+
// Correct since if statement
42+
if(some_check(with, params)==
43+
some_value)
44+
{
45+
do_something();
46+
}
47+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.cpp
3+
4+
^Total errors found: 0$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--

scripts/cpplint.py

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4686,9 +4686,75 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
46864686
if linenum>0:
46874687
while prev_initial_spaces < len(prev) and prev[prev_initial_spaces] == ' ':
46884688
prev_initial_spaces += 1
4689-
if Search(r'\([^\)]*,$', elided_line) or Search(r'\(\[^\)]*, $', elided_line):
4690-
error(filename, linenum, 'whitespace/indent', 4,
4691-
'If parameters or arguments require a line break, each parameter should be put on its own line.')
4689+
# here a regex isn't sufficent we need a stack to match brackets
4690+
# because even an open bracket and a , at the end might just be function call
4691+
# as a parameter.
4692+
# Instead the rule we try to apply here is:
4693+
# - if we find an opening bracket, we find the matching closing bracket
4694+
# - if the bracket is on a different line we require all of the parameters to be on a separate line
4695+
# - if there is another opening bracket Skip to the closing bracket as will be checked in a subsequent line check
4696+
# - ignore the line if it is a for/if etc since rules are different
4697+
4698+
# Look for an opening bracket that doesn't have a semi-colon on the same line
4699+
bracket_search = Search(r'(?P<bracket>\()[^;]*,[^;]*$', elided_line)
4700+
4701+
# Exclude the check if any of these keywords are present
4702+
# They could trip us up as they have different formatting rules to functions
4703+
keyword_search = Search(r'\b(if|for|while|catch|switch)\b', elided_line)
4704+
4705+
if bracket_search and not keyword_search:
4706+
open_bracket_pos = bracket_search.start('bracket')
4707+
close_line, close_linenum, close_pos = CloseExpression(clean_lines, linenum, open_bracket_pos)
4708+
if close_pos != -1:
4709+
# If the closing line is different from the opening line we need to
4710+
# verify that each of the parameters are on separate lines
4711+
if close_linenum != linenum:
4712+
# The first line needs to have no parameters on it
4713+
if(Search(r'\(.+', elided_line)):
4714+
error(filename, linenum, 'whitespace/indent', 4,
4715+
'If parameters or arguments require a line break, each parameter should be put on its own line.')
4716+
4717+
# For each line afer we need to verify it consists of exactly one parameter
4718+
# Except if we find an opening bracket - in this case we ignore everything until the closing
4719+
# bracket (any errors within these brackets will be picked up when we check this line)
4720+
start_linenum = linenum + 1
4721+
while(start_linenum < close_linenum):
4722+
arg_line = clean_lines.elided[start_linenum]
4723+
nested_bracket_search = Search('\(', arg_line)
4724+
if nested_bracket_search:
4725+
nested_open_bracket_pos = nested_bracket_search.start()
4726+
# Just because we are calling a nested function doesn't mean
4727+
# we allow multiple parameters on the line
4728+
if(Search(',', arg_line[:nested_open_bracket_pos])):
4729+
error(filename, start_linenum, 'whitespace/indent', 4,
4730+
'If parameters or arguments require a line break, each parameter should be put on its own line.')
4731+
4732+
nested_close_line, nested_close_linenum, _ = CloseExpression(clean_lines, start_linenum, nested_open_bracket_pos)
4733+
4734+
# If anything other closing statements or commas appear there is another parameter after the nested call
4735+
if not Search(r'\)(,|\)|;)*', nested_close_line):
4736+
error(filename, start_linenum, 'whitespace/indent', 4,
4737+
'If parameters or arguments require a line break, each parameter should be put on its own line.')
4738+
# Skip to the end of the bracket
4739+
start_linenum = nested_close_linenum
4740+
4741+
start_linenum+=1
4742+
# For the final line we also need to check one parameter on it
4743+
# e.g. we require bracket on same line as last parameter
4744+
# foo(
4745+
# x);
4746+
if not Search(r'^\s*[^,]+\)', close_line):
4747+
# If this is true, the we failed because we just had the close bracket
4748+
if Search(r'[^,]*\)', close_line):
4749+
error(filename, close_linenum, 'whitespace/indent', 4,
4750+
'If parameters or arguments require a line break, the closing bracket should be on the same line as the final parameter')
4751+
else:
4752+
# In this case the problem is we had a bracket
4753+
# i.e. more than one parameter on the last line
4754+
error(filename, close_linenum, 'whitespace/indent', 4,
4755+
'If parameters or arguments require a line break, each parameter should be put on its own line.')
4756+
4757+
46924758
if (Search(r'\([^\)]*$', elided_prev) and initial_spaces-2 != prev_initial_spaces) and not Search(r'for|while|if|;', elided_prev):
46934759
error(filename, linenum, 'whitespace/indent', 4,
46944760
'Indent of wrapped parenthesized expression or parameter or argument list should be 2')

0 commit comments

Comments
 (0)