From: Timur Tabi <timur@kernel.org>
To: cocci <cocci@systeme.lip6.fr>
Subject: [Cocci] Blank space in front of function definition name confuses spatch
Date: Tue, 22 Jan 2019 16:30:58 -0600 [thread overview]
Message-ID: <CAOZdJXUg+1M-ii-tEtYdjDyXuEUYbmHYSf-EqfzFh+OtuWLP7A@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 653 bytes --]
If I have a blank space in front of the return parameter and function
name, spatch gets confused and rejects the file. I've attached a
test.c and my nv_printf.cocci. If I remove the blank space before
"NV_STATUS" and "mycrazyfunc", everything works. But with the blank
space, it causes this error:
ERROR-RECOV: found sync '}' at line 14
parsing pass2: try again
ERROR-RECOV: found sync '}' at line 14
parsing pass3: try again
ERROR-RECOV: found sync '}' at line 14
parse error
= File "/home/ttabi/test.c", line 1, column 1, charpos = 1
around = 'NV_STATUS',
whole content = NV_STATUS
badcount: 13
BAD:!!!!! NV_STATUS
bad: mycrazyfunc
bad: (
[-- Attachment #2: nv_printf.cocci --]
[-- Type: application/octet-stream, Size: 8527 bytes --]
/*
* Coccinelle file to replace DBG_PRINTF() calls with NV_PRINTF()
*
* To work around an odd behavior of Coccinelle, we temporarily change
* the DBG_PRINTx statements into NV_PRINT2, and do all our work on that
* macro name. Only at the very end do we change NV_PRINT2 to NV_PRINTF.
* We do this so that Coccinelle won't touch existing NV_PRINTF statements.
*
* Python rules come in three parts:
* 1. A rule to determine if the Python code should be run
* 2. The Python code itself, inside a rule
* 3. A final rule that applies the output of the Python script
*/
// Remove the double-parentheses in DBG_PRINTF statements
@rule0@
@@
DBG_PRINTF(
-(
...
-)
);
// Replace DBG_PRINTF with NV_PRINTF2
@rule1 depends on rule0@
expression x;
expression list y;
@@
-DBG_PRINTF(x, y);
+NV_PRINTF2(y);
// Replace DBG_PRINT_STRING with NV_PRINTF2
@rule2@
expression list x;
@@
-DBG_PRINT_STRING(x);
+NV_PRINTF2(x);
// Replace DBG_PRINT_STRING_VALUE with NV_PRINTF2
@rule3@
expression x;
expression list y;
@@
-DBG_PRINT_STRING_VALUE(x, y);
+NV_PRINTF2(x, "%s 0x%x\n", y);
// Replace DBG_PRINT_STRING_PTR with NV_PRINTF2
@rule4@
expression x;
expression list y;
@@
-DBG_PRINT_STRING_PTR(x, y);
+NV_PRINTF2(x, "%s %p\n", y);
// Replace DBG_PRINT_STRING_VAL64 with NV_PRINTF2
@rule5@
expression x;
expression list y;
@@
-DBG_PRINT_STRING_VAL64(x, y);
+NV_PRINTF2(x, "%s 0x%llx\n", y);
// Collect all the previous rules as a dependecy, so that the rules below
// can depend only on "rules" instead of "rule1 || rule2 || ..."
@rules depends on rule1 || rule2 || rule3 || rule4 || rule5@
@@
NV_PRINTF2
// Replace the DBG_xxx or DEBUGLEVEL_xxx with LEVEL_xxx
@depends on rules@
@@
NV_PRINTF2(...,
-DBG_LEVEL_REGTRACE
+LEVEL_SILENT
, ...);
@depends on rules@
@@
NV_PRINTF2(...,
-\(DBG_LEVEL_INFO \| DEBUGLEVEL_TRACEINFO \| DBG_LEVEL_SETUPINFO \| DEBUGLEVEL_SETUPINFO\)
+LEVEL_INFO
, ...);
@depends on rules@
@@
NV_PRINTF2(...,
-\(DBG_LEVEL_USERERRORS \| DEBUGLEVEL_USERERRORS \| DBG_LEVEL_NOTICE\)
+LEVEL_NOTICE
, ...);
@depends on rules@
@@
NV_PRINTF2(...,
-\(DBG_LEVEL_WARNINGS \| DEBUGLEVEL_WARNINGS\)
+LEVEL_WARNING
, ...);
@depends on rules@
@@
NV_PRINTF2(...,
-\(DBG_LEVEL_ERRORS \| DEBUGLEVEL_ERRORS\)
+LEVEL_ERROR
, ...);
@depends on rules@
@@
NV_PRINTF2(...,
-DBG_LEVEL_HW_ERROR
+LEVEL_HW_ERROR
, ...);
@depends on rules@
@@
NV_PRINTF2(...,
-DBG_LEVEL_FATAL
+LEVEL_FATAL
, ...);
// -------------------------------
// Use Python to clean up the string literals.
// Comments are still C-style though
@r depends on rules@
expression x;
constant char[] c;
position p1;
@@
NV_PRINTF2(x, c@p1, ...)
@script:python s@
c << r.c;
c2;
p1 << r.p1;
@@
import re
import sys
// Convert a malformed multi-line string literal into one line
// Coccinelle sometimes takes care of this for us, but sometimes it doesn't
c = re.sub(r'\\\n[ ]*', '', c, re.DOTALL)
// Combine "xxx" "yyy" into "xxxyyy"
while True:
m = re.match(r'(.*)"([^"]+)" "(.*)', c)
if not m:
break
c = '%s"%s%s' % (m.group(1), m.group(2), m.group(3))
// Warn if there's no delimeter between two merged strings. This is
// usually a sign that someone forgot to put a blank space between
// two words.
if m.group(2)[-2:] != r'\n' and m.group(2)[-1].isalpha() and m.group(3)[0].isalpha():
print >>sys.stderr, 'Warning: string in function %s may have concatenated two words: "%s" and "%s"' % (p1[0].current_element, m.group(2).split()[-1], m.group(3).split()[0])
// Remove blank spaces before \n
// I don't know why we need four backslashes, but we do
c = re.sub(r'\s+\\n', '\\\\n', c)
// Remove the "NXXX: " prefix
c = re.sub(r'"N[A-Z]+(: |:| )', '"', c, 1)
// If the string ends with \n " then remove the spaces between \n and "
// Chances are, it's typo instead of an indentation for the next line
c = re.sub(r'\\n\s+"$', '\\\\n"', c, 1)
if len(c) > 3 and c.startswith(r'"\n'):
print >>sys.stderr, 'Warning: string in function %s begins with a newline' % p1[0].current_element
print >>sys.stderr, c
if c.endswith('"') and not c.endswith(r'\n"'):
print >>sys.stderr, 'Warning: missing \\n in function %s' % p1[0].current_element
print >>sys.stderr, c
// Finally, return the string
coccinelle.c2 = c
@depends on rules@
expression x;
constant char[] r.c;
identifier s.c2;
position r.p1;
@@
NV_PRINTF2(x,
-c@p1
+c2
,...)
// -------------------------------
// Replace __func__ with __FUNCTION__
@rx depends on rules@
symbol __func__;
@@
NV_PRINTF2(...
-,__func__
+,__FUNCTION__
,...)
// -------------------------------
// Look for NV_PRINTF2 calls that have __FUNCTION__ as the first parameter
@r2 depends on rules@
constant char[] c;
expression x;
symbol __func__;
@@
NV_PRINTF2(x, c, __FUNCTION__, ...)
// Get rid of __FUNCTION__ at the beginning of the string
@script:python s2@
c << r2.c;
c2;
@@
import re
coccinelle.c2 = re.sub('%s[:\(\)]*[ ]?', '', c, 1)
@depends on rules@
expression x;
constant char[] r2.c;
identifier s2.c2;
@@
NV_PRINTF2(x,
-c, __FUNCTION__
+c2
,...);
// -------------------------------
// Look for NV_PRINTF2 calls that have __FUNCTION__ as the last parameter
@r3 depends on rules@
constant char[] c;
expression x;
symbol __func__;
@@
NV_PRINTF2(x, c, ..., __FUNCTION__)
// Get rid of __FUNCTION__ at the end of the string
@script:python s3@
c << r3.c;
c2;
@@
import re
// Find the last [: ]*%s, and remove it
pos = [i.span() for i in re.finditer('[: ]*%s', c)][-1]
c = c[:pos[0]] + c[pos[1]:]
// Also remove the word "in" if it's the last word in the string,
// because that's supposed to be "in <function>", which no longer
// makes sense.
coccinelle.c2 = re.sub(' in \\\\n"$', '\n"', c)
@depends on rules@
expression x;
constant char[] r3.c;
identifier s3.c2;
@@
NV_PRINTF2(x,
-c
+c2
,...
-,__FUNCTION__
);
// -------------------------------
// Look for NV_PRINTF2 calls that have the function name in the string
@r4 depends on rules@
expression x;
constant char[] c;
position p1;
@@
NV_PRINTF2(x@p1, c, ...)
// Get rid of the function name at the beginning of the string
@script:python s4@
c << r4.c;
c2;
p1 << r4.p1;
@@
import re
f = p1[0].current_element
coccinelle.c2 = re.sub('"%s[:\(\)]*[ ]?' % f, '"', c, 1)
@depends on rules@
expression x;
constant char[] r4.c;
identifier s4.c2;
position r4.p1;
@@
NV_PRINTF2(x@p1,
-c
+c2
,...);
// -------------------------------
// Rewrap the string literal if it's too long
@r5 depends on rules@
expression x;
constant char[] c;
position p1;
@@
NV_PRINTF2(x, c@p1, ...)
@script:python s5@
c << r5.c;
c2;
p1 << r5.p1;
@@
import re
import textwrap
import shlex
import sys
c2 = ''
nl = r'\n'
// Break up the parameter into individual string literals and iterate over them
// See https://stackoverflow.com/questions/53857669
//strings = re.match(r"\s*((?:\\[\S\s]|[^\"\\])+|\"[^\"\\]*(?:\\[\S\s][^\"\\]*)*\")\s*" , c)
for string in re.findall(r'"[^"\\]*(?:\\.[^"\\]*)*"|\S+', c):
// Break up long strings literals. Coccinelle will place them on separate lines.
line = string.strip()
if not line.startswith('"'):
c2 += line + ' '
continue
line = line[1:-1]
lines = [s+nl for s in line.split(nl)]
if line[-2:] == nl:
// split() adds an extra blank string if the input string ends in a \n
del lines[-1]
else:
lines[-1] = lines[-1][:-2]
// Merge a stand-alone \n with the adjacent string
while lines[0] == nl and len(lines) > 1:
lines[1] = nl + lines[1]
del lines[0]
i = 1
while i < len(lines):
if lines[i] == nl:
lines[i-1] += nl
del lines[i]
else:
i += 1
// All strings are now perfect, so wrap each one.
for l in lines:
if len(l) > 80:
for l2 in textwrap.wrap(l, width = 70, expand_tabs = False,
replace_whitespace = False, drop_whitespace = False,
break_long_words = False, break_on_hyphens = False):
c2 += '"%s" ' % l2
else:
c2 += '"%s" ' % l
coccinelle.c2 = c2
@depends on rules@
expression x;
constant char[] r5.c;
identifier s5.c2;
position r5.p1;
@@
NV_PRINTF2(x,
-c@p1
+c2
,...)
// Remove any unnecessary braces
//@depends on rules@
//expression list x;
//@@
//-{
//NV_PRINTF2(x);
//-}
// Finally, change NV_PRINT2 to NV_PRINTF. This has the side-effect of
// also compressing all the parameters into as few lines as possible.
@depends on rules@
expression list x;
@@
-NV_PRINTF2(x)
+NV_PRINTF(x)
[-- Attachment #3: test.c --]
[-- Type: text/x-csrc, Size: 325 bytes --]
NV_STATUS
mycrazyfunc
(
POBJGPU pLocalGpu,
POBJBUS pLocalBus
)
{
DBG_PRINTF((DBG_MODULE_OS, DBG_LEVEL_ERRORS,
"NVRM: %s: this is a test \
of multiline " NvP64_fmt " strings %p\n ",
__FUNCTION__,
p1,
p2));
}
[-- Attachment #4: Type: text/plain, Size: 136 bytes --]
_______________________________________________
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci
next reply other threads:[~2019-01-22 22:31 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-22 22:30 Timur Tabi [this message]
2019-01-23 6:19 ` [Cocci] Blank space in front of function definition name confuses spatch Julia Lawall
2019-01-24 20:19 ` Julia Lawall
2019-01-28 21:50 ` Timur Tabi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAOZdJXUg+1M-ii-tEtYdjDyXuEUYbmHYSf-EqfzFh+OtuWLP7A@mail.gmail.com \
--to=timur@kernel.org \
--cc=cocci@systeme.lip6.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).