adlint 1.0.0 → 1.2.0

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