adlint 1.4.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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