adlint 1.0.0 → 1.2.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 (54) hide show
  1. data/AUTHORS +3 -2
  2. data/ChangeLog +208 -63
  3. data/MANIFEST +4 -0
  4. data/NEWS +24 -5
  5. data/etc/conf.d/fallback/traits.erb +1 -1
  6. data/etc/conf.d/i686-cygwin/traits-gcc_4.3.4.erb +1 -1
  7. data/etc/conf.d/i686-devkit/traits-gcc_4.5.2.erb +1 -1
  8. data/etc/conf.d/i686-linux/traits-gcc_4.5.1.erb +1 -1
  9. data/etc/conf.d/i686-mingw/traits-gcc_4.6.1.erb +1 -1
  10. data/etc/mesg.d/en_US/messages.yml +3 -3
  11. data/etc/mesg.d/ja_JP/messages.yml +4 -4
  12. data/lib/adlint/c/builtin.rb +3 -3
  13. data/lib/adlint/c/ctrlexpr.rb +7 -11
  14. data/lib/adlint/c/expr.rb +548 -363
  15. data/lib/adlint/c/interp.rb +233 -525
  16. data/lib/adlint/c/mediator.rb +1 -0
  17. data/lib/adlint/c/message.rb +144 -1
  18. data/lib/adlint/c/object.rb +15 -6
  19. data/lib/adlint/c/parser.rb +170 -128
  20. data/lib/adlint/c/parser.y +36 -0
  21. data/lib/adlint/c/phase.rb +4 -0
  22. data/lib/adlint/c/seqp.rb +72 -0
  23. data/lib/adlint/c/syntax.rb +254 -3
  24. data/lib/adlint/c.rb +1 -0
  25. data/lib/adlint/cpp/code.rb +2 -2
  26. data/lib/adlint/cpp/eval.rb +29 -13
  27. data/lib/adlint/cpp/message.rb +71 -70
  28. data/lib/adlint/cpp/message_shima.rb +100 -0
  29. data/lib/adlint/cpp/phase.rb +4 -0
  30. data/lib/adlint/cpp/syntax.rb +5 -1
  31. data/lib/adlint/cpp.rb +1 -0
  32. data/lib/adlint/message.rb +6 -3
  33. data/lib/adlint/traits.rb +1 -1
  34. data/lib/adlint/version.rb +5 -5
  35. data/share/demo/Makefile +3 -1
  36. data/share/demo/bad_line/bad_line.c +27 -0
  37. data/share/demo/sequence_point/sequence_point.c +31 -0
  38. data/share/doc/adlint_on_vim_en.png +0 -0
  39. data/share/doc/adlint_on_vim_ja.png +0 -0
  40. data/share/doc/developers_guide_ja.html +3 -3
  41. data/share/doc/developers_guide_ja.texi +1 -1
  42. data/share/doc/users_guide_en.html +3118 -41
  43. data/share/doc/users_guide_en.texi +3090 -37
  44. data/share/doc/users_guide_ja.html +3120 -47
  45. data/share/doc/users_guide_ja.texi +3106 -65
  46. data/share/sample/ctags-5.8/adlint/GNUmakefile +13 -1
  47. data/share/sample/ctags-5.8/adlint/adlint_cinit.h +14 -2
  48. data/share/sample/ctags-5.8/adlint/adlint_pinit.h +14 -4
  49. data/share/sample/ctags-5.8/adlint/adlint_traits.yml +14 -1
  50. data/share/sample/flex-2.5.35/adlint/GNUmakefile +13 -1
  51. data/share/sample/flex-2.5.35/adlint/adlint_cinit.h +14 -2
  52. data/share/sample/flex-2.5.35/adlint/adlint_pinit.h +14 -4
  53. data/share/sample/flex-2.5.35/adlint/adlint_traits.yml +14 -1
  54. metadata +6 -2
@@ -240,6 +240,7 @@ module C #:nodoc:
240
240
  def_delegator :interpreter, :notify_branch_ended
241
241
  def_delegator :interpreter, :notify_translation_unit_started
242
242
  def_delegator :interpreter, :notify_translation_unit_ended
243
+ def_delegator :interpreter, :notify_sequence_point_reached
243
244
 
244
245
  private
245
246
  def interpreter
@@ -6998,7 +6998,6 @@ module C #:nodoc:
6998
6998
  private
6999
6999
  def check(expression, variable)
7000
7000
  return if variable.scope.global? || variable.binding.memory.static?
7001
- return if variable.temporary?
7002
7001
 
7003
7002
  if variable.named? && variable.value.must_be_undefined?
7004
7003
  W(:W0459, expression.location, variable.name)
@@ -10544,6 +10543,150 @@ module C #:nodoc:
10544
10543
  end
10545
10544
  end
10546
10545
 
10546
+ class W0597 < PassiveMessageDetection
10547
+ def initialize(context)
10548
+ super
10549
+ interp = context[:c_interpreter]
10550
+ interp.on_sequence_point_reached += method(:commit_changes)
10551
+ interp.on_variable_value_updated += method(:update_variable)
10552
+ @update_count = Hash.new(0)
10553
+ end
10554
+
10555
+ private
10556
+ def commit_changes(sequence_point)
10557
+ @update_count.each do |var, count|
10558
+ W(:W0597, sequence_point.last_node.location, var.name) if count > 1
10559
+ end
10560
+ @update_count = Hash.new(0)
10561
+ end
10562
+
10563
+ def update_variable(expression, variable)
10564
+ @update_count[variable] += 1 if variable.named?
10565
+ end
10566
+ end
10567
+
10568
+ class W0598 < PassiveMessageDetection
10569
+ def initialize(context)
10570
+ super
10571
+ interp = context[:c_interpreter]
10572
+ interp.on_sequence_point_reached += method(:commit_changes)
10573
+ interp.on_variable_value_updated += method(:update_variable)
10574
+ @update_count = [Hash.new(0)]
10575
+ end
10576
+
10577
+ private
10578
+ def commit_changes(sequence_point)
10579
+ if sequence_point.obvious?
10580
+ updated_vars = @update_count.map { |hash| hash.keys }.flatten.uniq
10581
+ updated_vars.each do |var|
10582
+ if @update_count.count { |hash| hash.include?(var) } > 1
10583
+ if @update_count.map { |hash| hash[var] }.max == 1
10584
+ W(:W0598, sequence_point.last_node.location, var.name)
10585
+ end
10586
+ end
10587
+ end
10588
+ @update_count = [Hash.new(0)]
10589
+ else
10590
+ @update_count.push(Hash.new(0))
10591
+ end
10592
+ end
10593
+
10594
+ def update_variable(expression, variable)
10595
+ @update_count.last[variable] += 1 if variable.named?
10596
+ end
10597
+ end
10598
+
10599
+ class W0599 < PassiveMessageDetection
10600
+ def initialize(context)
10601
+ super
10602
+ interp = context[:c_interpreter]
10603
+ interp.on_sequence_point_reached += method(:commit_changes)
10604
+ interp.on_variable_value_referred += method(:refer_variable)
10605
+ interp.on_variable_value_updated += method(:update_variable)
10606
+ @refer_count = Hash.new(0)
10607
+ @update_count = Hash.new(0)
10608
+ end
10609
+
10610
+ private
10611
+ def commit_changes(sequence_point)
10612
+ (@refer_count.keys & @update_count.keys).each do |var|
10613
+ if @refer_count[var] > 0 && @update_count[var] > 0
10614
+ W(:W0599, sequence_point.last_node.location, var.name)
10615
+ end
10616
+ end
10617
+ @refer_count = Hash.new(0)
10618
+ @update_count = Hash.new(0)
10619
+ end
10620
+
10621
+ def refer_variable(expression, variable)
10622
+ @refer_count[variable] += 1 if variable.named?
10623
+ end
10624
+
10625
+ def update_variable(expression, variable)
10626
+ if variable.named?
10627
+ case expression
10628
+ when SimpleAssignmentExpression, CompoundAssignmentExpression
10629
+ # NOTE: The expression-statement `i = i + j;' should not be warned.
10630
+ # But the expression-statement `i = i++ + j;' should be warned.
10631
+ # So, side-effects of the assignment-expression are given
10632
+ # special treatment.
10633
+ else
10634
+ @update_count[variable] += 1
10635
+ end
10636
+ end
10637
+ end
10638
+ end
10639
+
10640
+ class W0600 < PassiveMessageDetection
10641
+ def initialize(context)
10642
+ super
10643
+ interp = context[:c_interpreter]
10644
+ interp.on_sequence_point_reached += method(:commit_changes)
10645
+ interp.on_variable_value_referred += method(:refer_variable)
10646
+ interp.on_variable_value_updated += method(:update_variable)
10647
+ @refer_count = [Hash.new(0)]
10648
+ @update_count = [Hash.new(0)]
10649
+ end
10650
+
10651
+ private
10652
+ def commit_changes(sequence_point)
10653
+ if sequence_point.obvious?
10654
+ updated_vars = @update_count.map { |hash| hash.keys }.flatten.uniq
10655
+ access_count = @refer_count.zip(@update_count)
10656
+
10657
+ updated_vars.each do |var|
10658
+ count = access_count.count { |rhash, uhash|
10659
+ rhash.include?(var) && !uhash.include?(var)
10660
+ }
10661
+ W(:W0600, sequence_point.last_node.location, var.name) if count > 0
10662
+ end
10663
+ @refer_count = [Hash.new(0)]
10664
+ @update_count = [Hash.new(0)]
10665
+ else
10666
+ @refer_count.push(Hash.new(0))
10667
+ @update_count.push(Hash.new(0))
10668
+ end
10669
+ end
10670
+
10671
+ def refer_variable(expression, variable)
10672
+ @refer_count.last[variable] += 1 if variable.named?
10673
+ end
10674
+
10675
+ def update_variable(expression, variable)
10676
+ if variable.named?
10677
+ case expression
10678
+ when SimpleAssignmentExpression, CompoundAssignmentExpression
10679
+ # NOTE: The expression-statement `i = i + j;' should not be warned.
10680
+ # But the expression-statement `i = i++ + j;' should be warned.
10681
+ # So, side-effects of the assignment-expression are given
10682
+ # special treatment.
10683
+ else
10684
+ @update_count.last[variable] += 1
10685
+ end
10686
+ end
10687
+ end
10688
+ end
10689
+
10547
10690
  class W0605 < PassiveMessageDetection
10548
10691
  def initialize(context)
10549
10692
  super
@@ -32,6 +32,7 @@
32
32
  require "adlint/util"
33
33
  require "adlint/c/value"
34
34
  require "adlint/c/scope"
35
+ require "adlint/c/seqp"
35
36
 
36
37
  module AdLint #:nodoc:
37
38
  module C #:nodoc:
@@ -221,7 +222,7 @@ module C #:nodoc:
221
222
 
222
223
  def inner_variable_at(index)
223
224
  if @type.array?
224
- # TODO: If linear serching is too slow, use an index of inner
225
+ # TODO: If linear searching is too slow, use an index of inner
225
226
  # variables.
226
227
  target_name = ArrayElementVariable.component_name_of(index)
227
228
  @inner_variables.find { |iv| iv.component_name == target_name }
@@ -232,7 +233,7 @@ module C #:nodoc:
232
233
 
233
234
  def inner_variable_named(name)
234
235
  if @type.composite?
235
- # TODO: If linear serching is too slow, use an index of inner
236
+ # TODO: If linear searching is too slow, use an index of inner
236
237
  # variables.
237
238
  target_name = CompositeMemberVariable.component_name_of(name)
238
239
  @inner_variables.find { |iv| iv.component_name == target_name }
@@ -624,9 +625,9 @@ module C #:nodoc:
624
625
  subclass_responsibility
625
626
  end
626
627
 
627
- def call(interpreter, args)
628
+ def call(interpreter, funcall_expr, args)
628
629
  assign_arguments_to_parameters(interpreter, args)
629
- return_values_via_pointer_arguments(interpreter, args)
630
+ return_values_via_pointer_arguments(interpreter, funcall_expr, args)
630
631
 
631
632
  if type.return_type.function?
632
633
  interpreter.temporary_variable
@@ -673,7 +674,7 @@ module C #:nodoc:
673
674
  end
674
675
  end
675
676
 
676
- def return_values_via_pointer_arguments(interpreter, args)
677
+ def return_values_via_pointer_arguments(interpreter, funcall_expr, args)
677
678
  args.zip(type.parameter_types).each do |(arg, expr), param_type|
678
679
  next if param_type && param_type.void?
679
680
  next unless arg.variable? && arg.value.scalar?
@@ -686,6 +687,14 @@ module C #:nodoc:
686
687
  pointee.designated_by_lvalue? && pointee.variable?
687
688
  pointee.assign!(pointee.type.return_value)
688
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
698
  end
690
699
  end
691
700
  end
@@ -705,7 +714,7 @@ module C #:nodoc:
705
714
  true
706
715
  end
707
716
 
708
- def call(interpreter, args)
717
+ def call(interpreter, funcall_expr, args)
709
718
  case name
710
719
  when "exit", "_exit", "abort"
711
720
  BreakEvent.of_return.throw