summaryrefslogtreecommitdiff
path: root/testsuite/gst-lint
blob: ce0875124b6ad8bc62deafd02ec7086fee57bf85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#!/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 check_lib_deprecated();
sub check_typo();

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();
	check_lib_deprecated();
	check_typo();

	# 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";
	}
}

#
# Check for use of deprecated functions
#
sub check_lib_deprecated()
{
	if (grep { /bzero/ } @lines) {
		print "E: change bzero() to memset()\n";
	}
}

#
# Check for typos
#
sub check_typo()
{
	if (grep { /;\s*;\s*$/ } @lines) {
		print "W: typo? \";;\"\n";
	}
}