diff --git a/Makefile.am b/Makefile.am index 9471cf7117860494ecc200acd1d756b1e8faf30d..9fe24fb65baeb22f34aa4398c80d8a227ca71357 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,7 +49,7 @@ EXTRA_DIST = \ build-aux/check-spacing.pl \ build-aux/header-ifdef.pl \ scripts/minimize-po.py \ - build-aux/mock-noinline.pl \ + scripts/mock-noinline.py \ scripts/prohibit-duplicate-header.py \ build-aux/syntax-check.mk \ build-aux/useless-if-before-free \ diff --git a/build-aux/mock-noinline.pl b/build-aux/mock-noinline.pl deleted file mode 100644 index b005b8d95e7dbe86068546248d998eb78a423eaf..0000000000000000000000000000000000000000 --- a/build-aux/mock-noinline.pl +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env perl - -my %noninlined; -my %mocked; - -# Functions in public header don't get the noinline annotation -# so whitelist them here -$noninlined{"virEventAddTimeout"} = 1; -# This one confuses the script as its defined in the mock file -# but is actually just a local helper -$noninlined{"virMockStatRedirect"} = 1; - -foreach my $arg (@ARGV) { - if ($arg =~ /\.h$/) { - #print "Scan header $arg\n"; - &scan_annotations($arg); - } elsif ($arg =~ /mock\.c$/) { - #print "Scan mock $arg\n"; - &scan_overrides($arg); - } -} - -my $warned = 0; -foreach my $func (keys %mocked) { - next if exists $noninlined{$func}; - - $warned++; - print STDERR "$func is mocked at $mocked{$func} but missing noinline annotation\n"; -} - -exit $warned ? 1 : 0; - - -sub scan_annotations { - my $file = shift; - - open FH, $file or die "cannot read $file: $!"; - - my $func; - while () { - if (/^\s*(\w+)\(/ || /^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(/) { - my $name = $1; - if ($name !~ /(?:G_GNUC|ATTRIBUTE)/) { - $func = $name; - } - } elsif (/^\s*$/) { - $func = undef; - } - if (/G_GNUC_NO_INLINE/) { - if (defined $func) { - $noninlined{$func} = 1; - } - } - } - - close FH -} - -sub scan_overrides { - my $file = shift; - - open FH, $file or die "cannot read $file: $!"; - - my $func; - while () { - if (/^(\w+)\(/ || /^\w+\s*(?:\*\s*)?(\w+)\(/) { - my $name = $1; - if ($name =~ /^vir/) { - $mocked{$name} = "$file:$."; - } - } - } - - close FH -} diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index f1e976ec769712dcd5ccd3c20fc3ce0e1abea3e1..7112f8235d1cd79961d69bb235fb088edf4c2b20 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -2180,8 +2180,8 @@ spacing-check: { echo '$(ME): incorrect formatting' 1>&2; exit 1; } mock-noinline: - $(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[ch]$$' | xargs \ - $(PERL) $(top_srcdir)/build-aux/mock-noinline.pl + $(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[ch]$$' | $(RUNUTF8) xargs \ + $(PYTHON) $(top_srcdir)/scripts/mock-noinline.py header-ifdef: $(AM_V_GEN)$(VC_LIST) | $(GREP) '\.[h]$$' | xargs \ diff --git a/scripts/mock-noinline.py b/scripts/mock-noinline.py new file mode 100644 index 0000000000000000000000000000000000000000..b338c5f0978ae07336dec12439bc2ce8ec6e7165 --- /dev/null +++ b/scripts/mock-noinline.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017-2019 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# . + +from __future__ import print_function + +import re +import sys + +noninlined = {} +mocked = {} + +# Functions in public header don't get the noinline annotation +# so whitelist them here +noninlined["virEventAddTimeout"] = True +# This one confuses the script as its defined in the mock file +# but is actually just a local helper +noninlined["virMockStatRedirect"] = True + + +def scan_annotations(filename): + with open(filename, "r") as fh: + func = None + for line in fh: + m = re.search(r'''^\s*(\w+)\(''', line) + if m is None: + m = re.search(r'''^(?:\w+\*?\s+)+(?:\*\s*)?(\w+)\(''', line) + if m is not None: + name = m.group(1) + if "ATTRIBUTE" not in name and "G_GNUC_" not in name: + func = name + elif line.isspace(): + func = None + + if "G_GNUC_NO_INLINE" in line: + if func is not None: + noninlined[func] = True + + +def scan_overrides(filename): + with open(filename, "r") as fh: + lineno = 0 + for line in fh: + lineno = lineno + 1 + + m = re.search(r'''^(\w+)\(''', line) + if m is None: + m = re.search(r'''^\w+\s*(?:\*\s*)?(\w+)\(''', line) + if m is not None: + name = m.group(1) + if name.startswith("vir"): + mocked[name] = "%s:%d" % (filename, lineno) + + +for filename in sys.argv[1:]: + if filename.endswith(".h"): + scan_annotations(filename) + elif filename.endswith("mock.c"): + scan_overrides(filename) + +warned = False +for func in mocked.keys(): + if func not in noninlined: + warned = True + print("%s is mocked at %s but missing noinline annotation" % + (func, mocked[func]), file=sys.stderr) + +if warned: + sys.exit(1) +sys.exit(0)