adlint 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/ChangeLog +413 -5
  2. data/MANIFEST +6 -0
  3. data/NEWS +43 -4
  4. data/etc/mesg.d/en_US/messages.yml +1 -1
  5. data/etc/mesg.d/ja_JP/messages.yml +1 -1
  6. data/lib/adlint/c.rb +1 -0
  7. data/lib/adlint/c/enum.rb +52 -0
  8. data/lib/adlint/c/expr.rb +43 -102
  9. data/lib/adlint/c/interp.rb +1 -1
  10. data/lib/adlint/c/mediator.rb +1 -0
  11. data/lib/adlint/c/message.rb +831 -49
  12. data/lib/adlint/c/message_shima.rb +236 -0
  13. data/lib/adlint/c/metric.rb +9 -0
  14. data/lib/adlint/c/object.rb +37 -32
  15. data/lib/adlint/c/parser.rb +7 -7
  16. data/lib/adlint/c/parser.y +7 -7
  17. data/lib/adlint/c/phase.rb +21 -0
  18. data/lib/adlint/c/syntax.rb +11 -4
  19. data/lib/adlint/c/type.rb +1 -1
  20. data/lib/adlint/cpp.rb +1 -0
  21. data/lib/adlint/cpp/asm.rb +73 -0
  22. data/lib/adlint/cpp/message.rb +13 -0
  23. data/lib/adlint/cpp/message_shima.rb +36 -0
  24. data/lib/adlint/cpp/phase.rb +3 -0
  25. data/lib/adlint/cpp/source.rb +9 -0
  26. data/lib/adlint/version.rb +3 -3
  27. data/share/demo/Makefile +4 -0
  28. data/share/demo/bad_conv/bad_conv.c +12 -0
  29. data/share/demo/bad_enum/bad_enum.c +48 -2
  30. data/share/demo/bad_label/bad_label.c +26 -0
  31. data/share/demo/bad_macro/bad_macro.c +3 -0
  32. data/share/demo/implicit_conv/implicit_conv.c +1 -0
  33. data/share/demo/inline_asm/inline_asm.c +18 -0
  34. data/share/demo/invalid_call/invalid_call.c +5 -0
  35. data/share/demo/multi_decl/multi_decl_1.c +30 -0
  36. data/share/demo/overflow/overflow.c +3 -3
  37. data/share/demo/redundant_select/redundant_select.c +25 -0
  38. data/share/demo/reserved_ident/reserved_ident.c +98 -0
  39. data/share/doc/developers_guide_ja.html +3 -3
  40. data/share/doc/developers_guide_ja.texi +1 -1
  41. data/share/doc/users_guide_en.html +234 -126
  42. data/share/doc/users_guide_en.texi +207 -98
  43. data/share/doc/users_guide_ja.html +247 -156
  44. data/share/doc/users_guide_ja.texi +221 -130
  45. data/share/sample/vim-7.3/adlint/xxd/adlint_traits.yml +1 -1
  46. metadata +8 -2
@@ -35,6 +35,53 @@ require "adlint/message"
35
35
  module AdLint #:nodoc:
36
36
  module C #:nodoc:
37
37
 
38
+ class W0573 < PassiveMessageDetection
39
+ def initialize(context)
40
+ super
41
+ interp = context[:c_interpreter]
42
+ interp.on_function_call_expr_evaled += method(:check)
43
+ @environ = interp.environment
44
+ end
45
+
46
+ private
47
+ def check(function_call_expression, function, arg_variables,
48
+ result_variable)
49
+ if function.named? && function.name =~ /\A.*scanf\z/
50
+ format = create_format(function_call_expression,
51
+ format_str_index_of(function_call_expression),
52
+ arg_variables, @environ)
53
+ return unless format
54
+
55
+ format.conversion_specifiers.each_with_index do |cs, index|
56
+ if cs.scanset && cs.scanset.include?("-")
57
+ W(:W0573, format.location)
58
+ break
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def format_str_index_of(function_call_expression)
65
+ function_call_expression.argument_expressions.index do |arg_expr|
66
+ arg_expr.kind_of?(StringLiteralSpecifier)
67
+ end
68
+ end
69
+
70
+ def create_format(function_call_expression,
71
+ format_str_index, arg_variables, environment)
72
+ if format_str_index
73
+ format_str =
74
+ function_call_expression.argument_expressions[format_str_index]
75
+ if format_str && format_str.literal.value =~ /\AL?"(.*)"\z/i
76
+ location = format_str.location
77
+ trailing_args = arg_variables[(format_str_index + 1)..-1] || []
78
+ return ScanfFormat.new($1, location, trailing_args, environment)
79
+ end
80
+ end
81
+ nil
82
+ end
83
+ end
84
+
38
85
  class W0606 < PassiveMessageDetection
39
86
  def initialize(context)
40
87
  super
@@ -55,6 +102,46 @@ module C #:nodoc:
55
102
  end
56
103
  end
57
104
 
105
+ class W0685 < W0573
106
+ def check(function_call_expression, function, arg_variables,
107
+ result_variable)
108
+ if function.named? && function.name =~ /\A.*scanf\z/
109
+ format = create_format(function_call_expression,
110
+ format_str_index_of(function_call_expression),
111
+ arg_variables, @environ)
112
+ return unless format
113
+
114
+ format.conversion_specifiers.each do |cs|
115
+ next unless cs.scanset
116
+
117
+ cs.scanset.scan(/(.)-(.)/).each do |lhs, rhs|
118
+ W(:W0685, format.location) if lhs.ord > rhs.ord
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ class W0686 < W0573
126
+ def check(function_call_expression, function, arg_variables,
127
+ result_variable)
128
+ if function.named? && function.name =~ /\A.*scanf\z/
129
+ format = create_format(function_call_expression,
130
+ format_str_index_of(function_call_expression),
131
+ arg_variables, @environ)
132
+ return unless format
133
+
134
+ format.conversion_specifiers.each do |cs|
135
+ next unless cs.scanset
136
+
137
+ unless cs.valid_scanset?
138
+ W(:W0686, format.location)
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+
58
145
  class W0698 < PassiveMessageDetection
59
146
  def initialize(context)
60
147
  super
@@ -114,6 +201,34 @@ module C #:nodoc:
114
201
  end
115
202
  end
116
203
 
204
+ class W0781 < PassiveMessageDetection
205
+ def initialize(context)
206
+ super
207
+ visitor = context[:c_visitor]
208
+ visitor.enter_switch_statement += method(:enter_switch_statement)
209
+ visitor.leave_switch_statement += method(:check)
210
+ visitor.enter_case_labeled_statement += method(:add_exec_path)
211
+ visitor.enter_default_labeled_statement += method(:add_exec_path)
212
+ @exec_path_nums = []
213
+ end
214
+
215
+ private
216
+ def enter_switch_statement(node)
217
+ @exec_path_nums.push(0)
218
+ end
219
+
220
+ def check(node)
221
+ if exec_path_num = @exec_path_nums.last and exec_path_num < 2
222
+ W(:W0781, node.location)
223
+ end
224
+ @exec_path_nums.pop
225
+ end
226
+
227
+ def add_exec_path(node)
228
+ @exec_path_nums[-1] += 1 if node.executed?
229
+ end
230
+ end
231
+
117
232
  class W0801 < PassiveMessageDetection
118
233
  def initialize(context)
119
234
  super
@@ -128,6 +243,127 @@ module C #:nodoc:
128
243
  end
129
244
  end
130
245
 
246
+ class W0809 < PassiveMessageDetection
247
+ def initialize(context)
248
+ super
249
+ visitor = context[:c_visitor]
250
+ visitor.enter_function_declaration += method(:check_function_name)
251
+ visitor.enter_variable_declaration += method(:check_variable_name)
252
+ visitor.enter_variable_definition += method(:check_variable_name)
253
+ visitor.enter_parameter_definition += method(:check_variable_name)
254
+ visitor.enter_typedef_declaration += method(:check_typedef_name)
255
+ visitor.enter_struct_type_declaration += method(:check_tag_name)
256
+ visitor.enter_union_type_declaration += method(:check_tag_name)
257
+ visitor.enter_enum_type_declaration += method(:check_tag_name)
258
+ visitor.enter_enumerator += method(:check_enumerator_name)
259
+ visitor.enter_kandr_function_definition += method(:enter_function)
260
+ visitor.enter_ansi_function_definition += method(:enter_function)
261
+ visitor.leave_kandr_function_definition += method(:leave_function)
262
+ visitor.leave_ansi_function_definition += method(:leave_function)
263
+ @function_def_level = 0
264
+ end
265
+
266
+ private
267
+ def check_function_name(function_decl)
268
+ check_object_name(function_decl)
269
+ end
270
+
271
+ def check_variable_name(variable_decl_or_def)
272
+ check_object_name(variable_decl_or_def)
273
+ end
274
+
275
+ def check_typedef_name(typedef_decl)
276
+ if typedef_decl.identifier
277
+ case name = typedef_decl.identifier.value
278
+ when /\A__/, /\A_[A-Z]/, /\A_/
279
+ W(:W0809, typedef_decl.location, name)
280
+ end
281
+ end
282
+ end
283
+
284
+ def check_tag_name(type_decl)
285
+ if type_decl.identifier
286
+ case name = type_decl.identifier.value
287
+ when /\A__adlint/
288
+ # NOTE: To ignore AdLint internal tag names.
289
+ when /\A__/, /\A_[A-Z]/, /\A_/
290
+ W(:W0809, type_decl.location, name)
291
+ end
292
+ end
293
+ end
294
+
295
+ def check_enumerator_name(enumerator)
296
+ if enumerator.identifier
297
+ case name = enumerator.identifier.value
298
+ when /\A__/, /\A_[A-Z]/, /\A_/
299
+ W(:W0809, enumerator.location, name)
300
+ end
301
+ end
302
+ end
303
+
304
+ def enter_function(node)
305
+ check_object_name(node)
306
+ @function_def_level += 1
307
+ end
308
+
309
+ def leave_function(node)
310
+ @function_def_level -= 1
311
+ end
312
+
313
+ def check_object_name(decl_or_def)
314
+ if decl_or_def.identifier
315
+ case name = decl_or_def.identifier.value
316
+ when /\A__/, /\A_[A-Z]/
317
+ W(:W0809, decl_or_def.location, name)
318
+ when /\A_/
319
+ check_filelocal_object_name(name, decl_or_def)
320
+ end
321
+ end
322
+ end
323
+
324
+ def check_filelocal_object_name(name, decl_or_def)
325
+ if @function_def_level == 0
326
+ storage_class_specifier = decl_or_def.storage_class_specifier
327
+ if storage_class_specifier && storage_class_specifier.type == :STATIC
328
+ W(:W0809, decl_or_def.location, name)
329
+ end
330
+ end
331
+ end
332
+ end
333
+
334
+ class W1030 < PassiveMessageDetection
335
+ def initialize(context)
336
+ super
337
+ visitor = context[:c_visitor]
338
+ visitor.enter_generic_labeled_statement += method(:check)
339
+ visitor.enter_ansi_function_definition += method(:enter_function)
340
+ visitor.leave_ansi_function_definition += method(:leave_function)
341
+ visitor.enter_kandr_function_definition += method(:enter_function)
342
+ visitor.leave_kandr_function_definition += method(:leave_function)
343
+ @labels = nil
344
+ end
345
+
346
+ private
347
+ def check(generic_labeled_statement)
348
+ return unless @labels
349
+
350
+ label = generic_labeled_statement.label
351
+ if @labels.include?(label.value)
352
+ W(:W1030, label.location, label.value)
353
+ else
354
+ @labels.add(label.value)
355
+ end
356
+ end
357
+
358
+ def enter_function(node)
359
+ @labels = Set.new
360
+ end
361
+
362
+ def leave_function(node)
363
+ @labels = nil
364
+ end
365
+ end
366
+
131
367
  class W1033 < PassiveMessageDetection
132
368
  def initialize(context)
133
369
  super
@@ -291,6 +291,7 @@ module C #:nodoc:
291
291
  interp.on_function_ended += method(:leave_function)
292
292
  interp.on_variable_defined += method(:define_variable)
293
293
  interp.on_parameter_defined += method(:define_variable)
294
+ interp.on_variable_referred += method(:refer_variable)
294
295
  interp.on_variable_value_referred += method(:read_variable)
295
296
  interp.on_variable_value_updated += method(:write_variable)
296
297
  @current_function = nil
@@ -329,6 +330,14 @@ module C #:nodoc:
329
330
  end
330
331
  end
331
332
 
333
+ def refer_variable(expression, variable)
334
+ return unless @current_function
335
+
336
+ if variable.named? && @variables[variable.name]
337
+ @variables[variable.name] += 1
338
+ end
339
+ end
340
+
332
341
  def read_variable(expression, variable)
333
342
  return unless @current_function
334
343
 
@@ -661,14 +661,19 @@ module C #:nodoc:
661
661
  interpreter.do_conversion(arg, param_type) ||
662
662
  interpreter.temporary_variable(param_type)
663
663
  else
664
- next
664
+ converted = arg
665
665
  end
666
666
  else
667
667
  converted = interpreter.do_default_argument_promotion(arg)
668
- next if arg.type.same_as?(converted.type)
669
668
  end
670
669
 
671
- if converted
670
+ # NOTE: Value of the argument is referred when the assignment to the
671
+ # parameter is performed.
672
+ if arg.variable? && !arg.type.array?
673
+ interpreter.notify_variable_value_referred(expr, arg)
674
+ end
675
+
676
+ if converted && arg != converted
672
677
  interpreter.notify_implicit_conv_performed(expr, arg, converted)
673
678
  end
674
679
  end
@@ -677,26 +682,40 @@ module C #:nodoc:
677
682
  def return_values_via_pointer_arguments(interpreter, funcall_expr, args)
678
683
  args.zip(type.parameter_types).each do |(arg, expr), param_type|
679
684
  next if param_type && param_type.void?
680
- next unless arg.variable? && arg.value.scalar?
685
+ next unless arg.variable? && (arg.type.pointer? || arg.type.array?)
681
686
 
682
687
  param_type = param_type.unqualify if param_type
683
688
 
684
- if param_type && param_type.pointer? && !param_type.base_type.const? or
685
- param_type.nil? && arg.type.pointer?
686
- if pointee = interpreter.pointee_of(arg) and
687
- pointee.designated_by_lvalue? && pointee.variable?
688
- pointee.assign!(pointee.type.return_value)
689
- interpreter.notify_variable_value_updated(expr, pointee)
690
-
691
- # NOTE: Returning a value via a pointer parameter can be considered
692
- # as an evaluation of a statement-expression with a
693
- # simple-assignment-expression.
694
- # Control will reach to a sequence-point at the end of a full
695
- # expression.
696
- interpreter.notify_sequence_point_reached(
697
- SequencePoint.new(funcall_expr, false))
689
+ case
690
+ when param_type.nil? && (arg.type.pointer? || arg.type.array?),
691
+ param_type && param_type.pointer? && !param_type.base_type.const?,
692
+ param_type && param_type.array? && !param_type.base_type.const?
693
+ else
694
+ next
695
+ end
696
+
697
+ case
698
+ when arg.type.pointer?
699
+ pointee = interpreter.pointee_of(arg)
700
+ if pointee && pointee.designated_by_lvalue? && pointee.variable?
701
+ sink = pointee
702
+ else
703
+ next
698
704
  end
705
+ when arg.type.array?
706
+ sink = arg
699
707
  end
708
+
709
+ sink.assign!(sink.type.return_value)
710
+ interpreter.notify_variable_value_updated(expr, sink)
711
+
712
+ # NOTE: Returning a value via a pointer parameter can be considered as
713
+ # an evaluation of a statement-expression with a
714
+ # simple-assignment-expression.
715
+ # Control will reach to a sequence-point at the end of a full
716
+ # expression.
717
+ interpreter.notify_sequence_point_reached(
718
+ SequencePoint.new(funcall_expr, false))
700
719
  end
701
720
  end
702
721
  end
@@ -1009,19 +1028,5 @@ module C #:nodoc:
1009
1028
  end
1010
1029
  end
1011
1030
 
1012
- class EnumeratorTable
1013
- def initialize
1014
- @enumerators = {}
1015
- end
1016
-
1017
- def define(enumerator)
1018
- @enumerators[enumerator.identifier.value] = enumerator
1019
- end
1020
-
1021
- def lookup(name_str)
1022
- @enumerators[name_str]
1023
- end
1024
- end
1025
-
1026
1031
  end
1027
1032
  end
@@ -70,7 +70,7 @@ def value_of(token)
70
70
  token == "$" ? "EOF" : token.value
71
71
  end
72
72
 
73
- def create_unnamed_type_name(base_token)
73
+ def create_unnamed_tag_name(base_token)
74
74
  Token.new(:IDENTIFIER, "__adlint__unnamed_#{@unnamed_type_no += 1}",
75
75
  base_token.location)
76
76
  end
@@ -2342,7 +2342,7 @@ module_eval(<<'.,.,', 'parser.y', 904)
2342
2342
  def _reduce_126(val, _values, result)
2343
2343
  checkpoint(val[0].location)
2344
2344
 
2345
- result = StructSpecifier.new(create_unnamed_type_name(val[0]), val[2])
2345
+ result = StructSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
2346
2346
  result.head_token = val[0]
2347
2347
  result.tail_token = val[3]
2348
2348
 
@@ -2354,7 +2354,7 @@ module_eval(<<'.,.,', 'parser.y', 912)
2354
2354
  def _reduce_127(val, _values, result)
2355
2355
  checkpoint(val[0].location)
2356
2356
 
2357
- result = StructSpecifier.new(create_unnamed_type_name(val[0]), [])
2357
+ result = StructSpecifier.new(create_unnamed_tag_name(val[0]), [])
2358
2358
  result.head_token = val[0]
2359
2359
  result.tail_token = val[2]
2360
2360
 
@@ -2366,7 +2366,7 @@ module_eval(<<'.,.,', 'parser.y', 920)
2366
2366
  def _reduce_128(val, _values, result)
2367
2367
  checkpoint(val[0].location)
2368
2368
 
2369
- result = UnionSpecifier.new(create_unnamed_type_name(val[0]), val[2])
2369
+ result = UnionSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
2370
2370
  result.head_token = val[0]
2371
2371
  result.tail_token = val[3]
2372
2372
 
@@ -2378,7 +2378,7 @@ module_eval(<<'.,.,', 'parser.y', 928)
2378
2378
  def _reduce_129(val, _values, result)
2379
2379
  checkpoint(val[0].location)
2380
2380
 
2381
- result = UnionSpecifier.new(create_unnamed_type_name(val[0]), [])
2381
+ result = UnionSpecifier.new(create_unnamed_tag_name(val[0]), [])
2382
2382
  result.head_token = val[0]
2383
2383
  result.tail_token = val[2]
2384
2384
 
@@ -2578,7 +2578,7 @@ module_eval(<<'.,.,', 'parser.y', 1076)
2578
2578
  def _reduce_146(val, _values, result)
2579
2579
  checkpoint(val[0].location)
2580
2580
 
2581
- result = EnumSpecifier.new(create_unnamed_type_name(val[0]), val[2])
2581
+ result = EnumSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
2582
2582
  result.head_token = val[0]
2583
2583
  result.tail_token = val[3]
2584
2584
 
@@ -2602,7 +2602,7 @@ module_eval(<<'.,.,', 'parser.y', 1092)
2602
2602
  def _reduce_148(val, _values, result)
2603
2603
  checkpoint(val[0].location)
2604
2604
 
2605
- result = EnumSpecifier.new(create_unnamed_type_name(val[0]), val[2])
2605
+ result = EnumSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
2606
2606
  result.head_token = val[0]
2607
2607
  result.tail_token = val[4]
2608
2608
 
@@ -904,7 +904,7 @@ struct_or_union_specifier
904
904
  {
905
905
  checkpoint(val[0].location)
906
906
 
907
- result = StructSpecifier.new(create_unnamed_type_name(val[0]), val[2])
907
+ result = StructSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
908
908
  result.head_token = val[0]
909
909
  result.tail_token = val[3]
910
910
  }
@@ -912,7 +912,7 @@ struct_or_union_specifier
912
912
  {
913
913
  checkpoint(val[0].location)
914
914
 
915
- result = StructSpecifier.new(create_unnamed_type_name(val[0]), [])
915
+ result = StructSpecifier.new(create_unnamed_tag_name(val[0]), [])
916
916
  result.head_token = val[0]
917
917
  result.tail_token = val[2]
918
918
  }
@@ -920,7 +920,7 @@ struct_or_union_specifier
920
920
  {
921
921
  checkpoint(val[0].location)
922
922
 
923
- result = UnionSpecifier.new(create_unnamed_type_name(val[0]), val[2])
923
+ result = UnionSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
924
924
  result.head_token = val[0]
925
925
  result.tail_token = val[3]
926
926
  }
@@ -928,7 +928,7 @@ struct_or_union_specifier
928
928
  {
929
929
  checkpoint(val[0].location)
930
930
 
931
- result = UnionSpecifier.new(create_unnamed_type_name(val[0]), [])
931
+ result = UnionSpecifier.new(create_unnamed_tag_name(val[0]), [])
932
932
  result.head_token = val[0]
933
933
  result.tail_token = val[2]
934
934
  }
@@ -1076,7 +1076,7 @@ enum_specifier
1076
1076
  {
1077
1077
  checkpoint(val[0].location)
1078
1078
 
1079
- result = EnumSpecifier.new(create_unnamed_type_name(val[0]), val[2])
1079
+ result = EnumSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
1080
1080
  result.head_token = val[0]
1081
1081
  result.tail_token = val[3]
1082
1082
  }
@@ -1092,7 +1092,7 @@ enum_specifier
1092
1092
  {
1093
1093
  checkpoint(val[0].location)
1094
1094
 
1095
- result = EnumSpecifier.new(create_unnamed_type_name(val[0]), val[2])
1095
+ result = EnumSpecifier.new(create_unnamed_tag_name(val[0]), val[2])
1096
1096
  result.head_token = val[0]
1097
1097
  result.tail_token = val[4]
1098
1098
  }
@@ -2078,7 +2078,7 @@ def value_of(token)
2078
2078
  token == "$" ? "EOF" : token.value
2079
2079
  end
2080
2080
 
2081
- def create_unnamed_type_name(base_token)
2081
+ def create_unnamed_tag_name(base_token)
2082
2082
  Token.new(:IDENTIFIER, "__adlint__unnamed_#{@unnamed_type_no += 1}",
2083
2083
  base_token.location)
2084
2084
  end