gstreamer/testsuite/gst-lint

461 lines
9.4 KiB
Text
Raw Normal View History

#!/usr/bin/perl -w
# vi: set ts=4:
#
#
# GStreamer developers: please add comments on any tests you think
# are dumb or have too many false positives.
#
#
# Future ideas:
# - spell check comments
# - check each function for at least one assertion (?)
# - check parameters that init/set/get have consistent types
# - check for gst_caps_set() without check for writeability
# - check .so files for stray symbols
#
#
# Random "other" testing ideas
# - load each plugin individually
#
sub check_copyright();
sub check_license();
sub check_buffer_alloc();
sub check_bad_includes();
sub check_begin_decls();
sub check_c99_comments();
sub check_carriage_returns();
sub check_printf_lld();
sub check_glibisms();
sub check_indentation();
sub check_gst_props_set();
sub check_deprecated();
sub check_config_h();
sub check_varargs_functions();
sub check_debugging();
sub check_old_typefind();
sub check_bad_casts();
sub check_old_plugin();
sub check_signal_new();
sub check_gnuc_const();
sub check_caps();
sub m_check_plugindir();
sub m_check_interfaces();
open FIND, "find . -name \"*.[ch]\" -print|";
foreach $filename (<FIND>) {
chomp $filename;
open FILE, "$filename";
@lines = <FILE>;
close FILE;
print "I: $filename\n";
# important stuff
check_bad_includes();
check_printf_lld();
check_gst_props_set();
check_deprecated();
check_config_h();
check_old_typefind();
check_old_plugin();
check_caps();
# less important stuff
if (0) {
check_copyright();
check_license();
check_gnuc_const();
check_begin_decls();
check_buffer_alloc();
check_c99_comments();
check_carriage_returns();
check_glibisms();
#check_indentation();
check_varargs_functions();
check_debugging();
check_bad_casts();
check_signal_new();
}
}
open FIND, "find . -name \"Makefile.am\" -print|";
foreach $filename (<FIND>) {
chomp $filename;
open FILE, "$filename";
@lines = <FILE>;
close FILE;
print "I: $filename\n";
m_check_plugindir();
m_check_interfaces();
}
#
# Every source file must have a copyright block
#
sub check_copyright()
{
if (! grep { /copyright/i; } @lines) {
print "E: no copyright block\n";
}
}
#
# Every source file should have a license statement
#
sub check_license()
{
if (grep { /Lesser General Public License/; } @lines) {
print "I: license is LGPL\n";
} elsif (grep { /Library General Public License/; } @lines) {
print "I: license is LGPL\n";
print "W: copyright header uses \"Library\" LGPL\n";
} elsif (grep { /General Public License/; } @lines) {
print "I: license is GPL\n";
} else {
print "E: unknown license or no copyright block\n";
}
}
#
# Suggest usage of gst_buffer_new_and_alloc()
#
sub check_buffer_alloc()
{
my $n = 0;
my $lineno = 1;
foreach $line (@lines){
if($line =~ /gst_buffer_new/){
$n=5;
}
if($n>0 && $line =~ /malloc/){
print "W: ($lineno) gst_buffer_new() followed by malloc(), suggest gst_buffer_new_and_alloc()\n";
return;
}
$n--;
$lineno++;
}
}
sub check_bad_includes()
{
#
# malloc.h is non-standard (and probably not what is indended)
#
if (grep { /^#include\s+<malloc.h>/; } @lines) {
print "E: bad header: malloc.h\n"
}
}
sub check_begin_decls()
{
#
# Prefer "G_BEGIN_DECLS" to 'extern "C" {'
#
if($filename =~ /\.h$/){
if (grep { /extern\s*\"C\"\s*/; } @lines) {
print "W: extern \"C\" { should be changed to G_BEGIN_DECLS,G_END_DECLS\n";
}elsif (!grep { /G_BEGIN_DECLS/; } @lines) {
print "E: header doesn't use G_BEGIN_DECLS\n";
}
}
}
#
# Prefer c89-style comments
#
sub check_c99_comments()
{
if (grep { /\/\//; } @lines) {
print "W: //-style comments should be converted to /* */\n"
}
}
#
# DOS end-of-line characters are just wrong
#
sub check_carriage_returns()
{
if (grep { /\r/; } @lines) {
print "E: source has carriage returns (DOS-style files)\n"
}
}
#
# Many uses of %lld are wrong. This could have a lot of false-positives
#
sub check_printf_lld()
{
if (grep { /\".*\%\d*ll[du].*\"/; } @lines) {
print "W: Possible \%lld or \%llu in printf format\n"
}
}
#
# Glib functions are preferred
#
sub check_glibisms()
{
if (grep { /\bcalloc\s*\(/; } @lines) {
print "E: use g_malloc0() instead of calloc()\n"
}
if (grep { /\bfree\s*\(/; } @lines) {
print "E: use g_free() instead of free()\n"
}
if (grep { /\bmalloc\s*\(/; } @lines) {
print "E: use g_malloc() instead of malloc()\n"
}
if (grep { /\bprintf\s*\(/; } @lines) {
print "E: use g_print() instead of printf()\n"
}
if (grep { /\brealloc\s*\(/; } @lines) {
print "E: use g_realloc() instead of realloc()\n"
}
}
#
# I don't think that indentation necessarily needs to be fixed, since
# it causes problems with patching and cvs annotate.
#
# This takes forever and isn't very useful
#
sub check_indentation()
{
my $changed_lines;
my $percent;
`indent -br -bad -cbi0 -cli2 -bls -l80 -ut -ce $filename -o .check_plugin.tmp`;
$changed_lines = `diff $filename .check_plugin.tmp | grep '^>' | wc -l`;
`rm -f .check_plugin.tmp`;
$percent = int(100 * $changed_lines / $#lines);
if($percent < 10){
print "I: indent changed $percent % of the lines\n";
}elsif($percent <20){
print "W: indent changed $percent % of the lines\n";
}else{
print "E: indent changed $percent % of the lines\n";
}
}
#
# gst_props_set() returns a value that should never be ignored
# may have false positives
#
sub check_gst_props_set()
{
if (grep { /^\s+gst_props_set\s*\(/; } @lines) {
print "E: return value of gst_props_set() possibly ignored\n";
}
}
#
# Check for some deprecated stuff (that _shouldn't_ be around anymore)
#
sub check_deprecated()
{
#
# Check for old GST_DEBUG() usage
# (none found)
#
if (grep { /GST_DEBUG\s*\(\s+\d/; } @lines) {
print "E: old-style GST_DEBUG()\n";
}
if (grep { /GST_INFO\s*\(\s+\d/; } @lines) {
print "E: old-style GST_DEBUG()\n";
}
if (grep { /GstEventFlags/; } @lines) {
print "W: who uses GstEventFlags\n";
}
if (grep { /g_type_class_ref/ } @lines) {
print "W: g_type_class_ref should be changed to g_type_class_peek_parent\n";
}
}
#
# Every .c file should include config.h before any other headers
# No .h file should include config.h
#
sub check_config_h()
{
if($filename =~ /\.c$/){
#
# config.h should be wrapped
#
my @includes = grep { /^#include/; } @lines;
if (!grep { /^#include\s+["<]config.h[">]/; } @includes) {
print "E: #include <config.h> missing\n";
}else{
if (!($includes[0] =~ /^#include\s+["<]config.h[">]/)){
print "E: #include <config.h> is not first include\n";
}
if(!grep { /^#ifdef HAVE_CONFIG_H/; } @lines) {
print "E: #include <config.h> not surrounded by #ifdef HAVE_CONFIG_H\n";
}
}
}
if($filename =~ /\.h$/){
if (grep { /^#include\s+["<]config.h[">]/; } @lines) {
print "E: headers should not #include <config.h>\n";
}
}
}
#
# Check for functions that take varargs to make sure they are
# named correctly
#
sub check_varargs_functions()
{
if($filename =~ /\.h$/){
if (grep { /varargs/; } @lines) {
print "I: has varargs\n";
}
}
}
#
# Debugging checks
#
sub check_debugging()
{
if (grep { /\Wg_print\W/ || /\Wprintf\W/ && /\Wfprintf\W/; } @lines) {
print "W: friendly libraries don't print to stdio or stderr\n";
}
if (grep { /GST_DEBUG.*\\n"/; } @lines) {
print "W: possible newline in GST_DEBUG()\n";
}
}
#
# check for plugindir=
#
sub m_check_plugindir()
{
if (grep { /plugindir\s*=/; } @lines) {
print "E: plugindir= is no longer necessary\n";
}
}
#
# check for old typefinding code
#
sub check_old_typefind()
{
if (grep { /GstTypeDefinition/ || /GstTypeFactory/ } @lines) {
print "E: old typefind interface has been removed\n";
}
}
#
# check for casts that we've deemed incorrect (fix the prototype)
#
sub check_bad_casts()
{
if (grep { /GBaseInitFunc/ || /GBaseFinalizeFunc/ ||
/GClassInitFunc/ || /GClassFinalizeFunc/ ||
/GInstanceInitFunc/ || /GInterfaceInitFunc/ ||
/GInterfaceFinalizeFunc/ } @lines) {
print "W: bad casts (fix prototype)\n";
}
if (grep { /\(\s*Gst[A-Z][A-Za-z]*\s*\*\s*\)/ } @lines ) {
print "W: use GST_XXX() instead of (GstXxx *)\n";
}
}
#
# check for old plugin code
#
sub check_old_plugin()
{
if (grep { /plugin_init.*GModule.*GstPlugin/ } @lines) {
print "E: old plugin interface detected\n";
}
if (grep { /GstPluginDesc.*plugin_desc/ } @lines) {
print "W: should use GST_PLUGIN_DEFINE() instead of GstPluginDesc\n";
}
}
#
# Check for calls to g_signal_new() with a callback type of G_TYPE_POINTER
#
sub check_signal_new()
{
my $n = 0;
my $lineno = 1;
foreach $line (@lines){
if($line =~ /g_signal_new/){
$n=5;
}
if($n>0 && $line =~ /G_TYPE_POINTER/){
print "W: ($lineno) g_signal_new() with callback type of G_TYPE_POINTER. Register and use a boxed type instead.\n";
return;
}
$n--;
$lineno++;
}
}
#
# Check that libgstinterfaces is in LDADD
#
sub m_check_interfaces()
{
if (grep { /libgstinterfaces.la/ } @lines) {
if (! grep { /libgstinterfaces_la/ } @lines) {
if (! grep { /_LDADD.*libgstinterfaces.la/ } @lines) {
print "E: libgstinterfaces.la not in LDADD\n";
}
}
}
}
#
# Check that get_type() functions return G_CONST_RETURN GType
#
sub check_gnuc_const()
{
my $n = 0;
my $lineno = 1;
foreach $line (@lines){
if($line =~ /GType.*get_type.*/ &&
!($line =~ /GType.*get_type.*G_GNUC_CONST/)) {
print "E: get_type function does not have G_GNUC_CONST attribute\n";
}
}
}
#
# Check caps usage
#
sub check_caps()
{
if (grep { /gst_pad_get_caps/ } @lines) {
print "E: elements should not call gst_pad_get_caps(), use gst_pad_get_allowed_caps()\n";
}
}