Skip to content

Commit

Permalink
Fix: Multiline function definition is now properly detected. No globa…
Browse files Browse the repository at this point in the history
…l variable warning in multiline function prototype. Also, counting the number of lines in functions was broken when a function contained sub-scopes ...
  • Loading branch information
Alexandre Gautier committed Aug 31, 2018
1 parent 8a8147f commit 0390748
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 34 deletions.
64 changes: 30 additions & 34 deletions betty-style.pl
Original file line number Diff line number Diff line change
Expand Up @@ -2248,8 +2248,9 @@ sub process {
$fixlinenr = -1;
my $nbfunc = 0;
my $infunc = 0;
my $infuncproto = 0;
my $funcprotovalid = 0; # Prevline ended a valid function prototype (no trailing ';')
my $inscope = 0;
my $infunction_params = 0;
my $funclines = 0;

foreach my $line (@lines) {
Expand Down Expand Up @@ -3629,7 +3630,8 @@ sub process {

# Check for global variables (not allowed).
if ($allow_global_variables == 0 &&
$inscope == 0 && $infunction_params == 0) {
$inscope == 0 &&
$infuncproto == 0) {
if ($line =~ /^\+\s*$Type\s*$Ident(?:\s+$Modifier)*(?:\s*=\s*.*)?;/ ||
$line =~ /^\+\s*$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(].*;/ ||
$line =~ /^\+\s*$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ ||
Expand Down Expand Up @@ -3706,21 +3708,6 @@ sub process {
}
}

#check if in function parameters section
if ($line =~ /\b$Type\s+$Ident\s*\(/ ||
$line =~ /\b$Ident(?:\s+|\s*\*+\s*)$Ident\s*\(/ &&
$line !~ /(?:else|if|while|for|switch)/) {
if ($line =~ /(\()/g) {
$infunction_params += $#-;
}
if ($line =~ /(\))/g) {
$infunction_params -= $#-;
}
}
if ($infunction_params > 0 && $line =~ /(\))/g) {
$infunction_params -= $#-;
}

# check for uses of DEFINE_PCI_DEVICE_TABLE
if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) {
if (WARN("DEFINE_PCI_DEVICE_TABLE",
Expand Down Expand Up @@ -3897,46 +3884,55 @@ sub process {
}
}

# Detect possible multiline function definition
if (!$infuncproto && $line =~ /^.((?:typedef\s*)?(?:(?:$Storage|$Inline)\s*(?:$Attribute\s*)?)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
$funcprotovalid = 0;
$infuncproto = 0;

if ($line =~ /\)\s*$/ && ($line =~ tr/(// == $line =~ tr/)//)) {
# Line ends with closing parenthesis -> End of function prototype
$funcprotovalid = 1;
}
else {
$infuncproto = 1;
}
}
elsif ($infuncproto && $line =~ /\)\s*$/ && ($line =~ tr/(// == ($line =~ tr/)// - 1))) {
# Line ends with closing parenthesis -> End of function prototype
$funcprotovalid = 1;
$infuncproto = 0;
}

# check number of functions
# and number of lines per function
if ($line =~ /({)/g) {
$inscope += $#-;
if ($prevline =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s && $inscope == 1) {
if ($funcprotovalid && $inscope == 1) {
$infunc = 1;
$nbfunc++;
$funclines = 0;
$funclines = -1;
if ($max_funcs > 0 && $nbfunc > $max_funcs) {
my $tmpline = $realline - 1;
if ($showfile) {
$prefix = "$realfile:$tmpline: ";
} elsif ($emacs) {
if ($file) {
$prefix = "$realfile:$tmpline: ";
} else {
$prefix = "$realfile:$tmpline: ";
}
}
$prefix = "$realfile:$tmpline: ";
ERROR("FUNCTIONS",
"More than $max_funcs functions in the file\n");
}
}
else {
$infunc = 0;
}
}
if ($line =~ /(})/g) {
$inscope -= $#-;
$infunc = 0 if ($inscope == 0);
$funclines = 0 if ($infunc == 0);
}

if ($inscope >= 1 && $infunc == 1) {
$funclines++;
if ($funclines > $max_func_length + 1) {
if ($funclines > $max_func_length) {
WARN("FUNCTIONS",
"More than $max_func_length lines in a function\n");
}
} else {
$funclines = 0;
}
# printf "[${infunc}][${inscope}|${infuncproto}][${funclines}]${line}\n";

# open braces for enum, union and struct go on the same line.
# if ($line =~ /^.\s*{/ &&
Expand Down
51 changes: 51 additions & 0 deletions tests/style/functions/functions6.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
int test_lexer(test_chain_t *chain)
{
const char *line = chain->line;
t_t *t = t_create();
char quote = 0;
int error = 0;

while (*line && !error)
{
const char *start = test_skip_space(line);
test_t *test = test_find_test(start);
const char *end = line;

if (test->test)
{
end = process_test(chain, &t, test, start);
}
else
{
end = test_skip_any(start, &quote);
if (end - start > 0)
{
if (!t->test &&
(t->test_type == MACRO_TEST_0 ||
t->test_type == MACRO_TEST_1 ||
t->test_type == MACRO_TEST_2 ||
t->test_type == MACRO_TEST_3))
{
t->test = hstrndup(start, end - start);
}
else
{
ARRAY_ADD(t->v, hstrndup(start, end - start), V_BUFFER_SIZE);
}
}
else if (*end)
{
end++;
}
}
line = end;
}
if (error)
{
hprintf("parsing error @ %s", line);
}
ARRAY_ADD(t->v, NULL, V_BUFFER_SIZE);
ARRAY_ADD(chain->root.tests, t, 2);
ARRAY_ADD(chain->root.tests, NULL, 1);
return (!quote);
}
9 changes: 9 additions & 0 deletions tests/style/functions/functions6.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
tests/style/functions/functions6.c:43: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:44: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:45: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:46: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:47: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:48: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:49: WARNING: More than 40 lines in a function
tests/style/functions/functions6.c:50: WARNING: More than 40 lines in a function
total: 0 errors, 8 warnings, 51 lines checked
8 changes: 8 additions & 0 deletions tests/style/variables/variables4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
static const char *test(
test_chain_t (*chain)(int),
test_t **cmd,
token_t *token,
const char *start)
{
return (start);
}
Empty file.

0 comments on commit 0390748

Please sign in to comment.