adlint 3.0.10 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. data/ChangeLog +67 -0
  2. data/MANIFEST +2 -0
  3. data/NEWS +10 -3
  4. data/etc/mesg.d/c_builtin/en_US/messages.yml +29 -1
  5. data/etc/mesg.d/c_builtin/ja_JP/messages.yml +29 -1
  6. data/etc/mesg.d/core/en_US/messages.yml +1 -1
  7. data/etc/mesg.d/core/ja_JP/messages.yml +1 -1
  8. data/features/code_check/W0003.feature +5 -0
  9. data/features/code_check/W0023.feature +32 -0
  10. data/features/code_check/W0024.feature +22 -0
  11. data/features/code_check/W0093.feature +71 -0
  12. data/features/code_check/W0097.feature +4 -0
  13. data/features/code_check/W0100.feature +10 -0
  14. data/features/code_check/W0119.feature +8 -0
  15. data/features/code_check/W0133.feature +8 -0
  16. data/features/code_check/W0134.feature +8 -0
  17. data/features/code_check/W0136.feature +8 -0
  18. data/features/code_check/W0138.feature +8 -0
  19. data/features/code_check/W0140.feature +8 -0
  20. data/features/code_check/W0142.feature +8 -0
  21. data/features/code_check/W0143.feature +8 -0
  22. data/features/code_check/W0144.feature +8 -0
  23. data/features/code_check/W0145.feature +8 -0
  24. data/features/code_check/W0146.feature +8 -0
  25. data/features/code_check/W0147.feature +8 -0
  26. data/features/code_check/W0148.feature +8 -0
  27. data/features/code_check/W0149.feature +8 -0
  28. data/features/code_check/W0150.feature +8 -0
  29. data/features/code_check/W0151.feature +8 -0
  30. data/features/code_check/W0152.feature +8 -0
  31. data/features/code_check/W0153.feature +8 -0
  32. data/features/code_check/W0154.feature +8 -0
  33. data/features/code_check/W0155.feature +8 -0
  34. data/features/code_check/W0156.feature +8 -0
  35. data/features/code_check/W0157.feature +8 -0
  36. data/features/code_check/W0158.feature +8 -0
  37. data/features/code_check/W0159.feature +8 -0
  38. data/features/code_check/W0160.feature +8 -0
  39. data/features/code_check/W0161.feature +8 -0
  40. data/features/code_check/W0162.feature +8 -0
  41. data/features/code_check/W0163.feature +8 -0
  42. data/features/code_check/W0164.feature +8 -0
  43. data/features/code_check/W0165.feature +8 -0
  44. data/features/code_check/W0166.feature +8 -0
  45. data/features/code_check/W0167.feature +8 -0
  46. data/features/code_check/W0168.feature +8 -0
  47. data/features/code_check/W0169.feature +8 -0
  48. data/features/code_check/W0170.feature +8 -0
  49. data/features/code_check/W0171.feature +8 -0
  50. data/features/code_check/W0172.feature +8 -0
  51. data/features/code_check/W0173.feature +8 -0
  52. data/features/code_check/W0174.feature +8 -0
  53. data/features/code_check/W0175.feature +8 -0
  54. data/features/code_check/W0176.feature +8 -0
  55. data/features/code_check/W0177.feature +8 -0
  56. data/features/code_check/W0178.feature +8 -0
  57. data/features/code_check/W0179.feature +8 -0
  58. data/features/code_check/W0180.feature +8 -0
  59. data/features/code_check/W0181.feature +8 -0
  60. data/features/code_check/W0250.feature +8 -0
  61. data/features/code_check/W0422.feature +194 -0
  62. data/features/code_check/W0459.feature +16 -0
  63. data/features/code_check/W0460.feature +342 -0
  64. data/features/code_check/W0461.feature +5 -0
  65. data/features/code_check/W0497.feature +12 -0
  66. data/features/code_check/W0499.feature +6 -0
  67. data/features/code_check/W0502.feature +6 -0
  68. data/features/code_check/W0570.feature +47 -0
  69. data/features/code_check/W0573.feature +8 -0
  70. data/features/code_check/W0582.feature +4 -0
  71. data/features/code_check/W0583.feature +4 -0
  72. data/features/code_check/W0584.feature +10 -0
  73. data/features/code_check/W0599.feature +10 -0
  74. data/features/code_check/W0644.feature +2 -0
  75. data/features/code_check/W0649.feature +14 -0
  76. data/features/code_check/W0650.feature +12 -0
  77. data/features/code_check/W0685.feature +10 -0
  78. data/features/code_check/W0686.feature +8 -0
  79. data/features/code_check/W0711.feature +2 -0
  80. data/features/code_check/W0712.feature +2 -0
  81. data/features/code_check/W0713.feature +2 -0
  82. data/features/code_check/W0714.feature +2 -0
  83. data/features/code_check/W0715.feature +2 -0
  84. data/features/code_check/W0718.feature +2 -0
  85. data/features/code_check/W0719.feature +8 -0
  86. data/features/code_check/W0732.feature +18 -0
  87. data/features/code_check/W0733.feature +18 -0
  88. data/features/code_check/W0734.feature +24 -0
  89. data/features/code_check/W0735.feature +24 -0
  90. data/features/code_check/W0747.feature +8 -0
  91. data/features/code_check/W0749.feature +8 -0
  92. data/features/code_check/W0750.feature +8 -0
  93. data/features/code_check/W0753.feature +8 -0
  94. data/features/code_check/W0754.feature +8 -0
  95. data/features/code_check/W0759.feature +8 -0
  96. data/features/code_check/W0760.feature +8 -0
  97. data/features/code_check/W0761.feature +8 -0
  98. data/features/code_check/W0762.feature +8 -0
  99. data/features/code_check/W0794.feature +6 -0
  100. data/features/code_check/W1050.feature +8 -0
  101. data/features/code_check/W1066.feature +8 -0
  102. data/features/code_check/W1067.feature +8 -0
  103. data/features/code_check/W1068.feature +8 -0
  104. data/features/code_check/W1071.feature +4 -0
  105. data/features/code_check/W9003.feature +2 -0
  106. data/lib/adlint/cc1.rb +1 -0
  107. data/lib/adlint/cc1/branch.rb +34 -13
  108. data/lib/adlint/cc1/conv.rb +3 -3
  109. data/lib/adlint/cc1/ctrlexpr.rb +12 -7
  110. data/lib/adlint/cc1/environ.rb +12 -2
  111. data/lib/adlint/cc1/expr.rb +10 -8
  112. data/lib/adlint/cc1/interp.rb +56 -49
  113. data/lib/adlint/cc1/mediator.rb +9 -5
  114. data/lib/adlint/cc1/object.rb +37 -34
  115. data/lib/adlint/cc1/trace.rb +287 -0
  116. data/lib/adlint/cc1/type.rb +15 -15
  117. data/lib/adlint/cc1/value.rb +823 -427
  118. data/lib/adlint/cpp/eval.rb +5 -2
  119. data/lib/adlint/cpp/source.rb +21 -22
  120. data/lib/adlint/exam/c_builtin/cc1_check.rb +1636 -1067
  121. data/lib/adlint/exam/c_builtin/cc1_check_shima.rb +28 -22
  122. data/lib/adlint/exam/c_builtin/cc1_code.rb +4 -4
  123. data/lib/adlint/exam/c_builtin/cc1_metric.rb +14 -14
  124. data/lib/adlint/location.rb +5 -7
  125. data/lib/adlint/metric.rb +2 -2
  126. data/lib/adlint/prelude.rb +6 -2
  127. data/lib/adlint/report.rb +2 -2
  128. data/lib/adlint/version.rb +3 -3
  129. data/share/doc/developers_guide_ja.html +10 -4
  130. data/share/doc/developers_guide_ja.texi +8 -2
  131. data/share/doc/users_guide_en.html +679 -72
  132. data/share/doc/users_guide_en.texi +557 -12
  133. data/share/doc/users_guide_ja.html +678 -74
  134. data/share/doc/users_guide_ja.texi +554 -13
  135. data/spec/adlint/cc1/ctrlexpr_spec.rb +20 -11
  136. data/spec/adlint/cc1/domain_spec.rb +9 -0
  137. metadata +4 -2
@@ -242,13 +242,13 @@ module Cc1 #:nodoc:
242
242
  binding.memory.read
243
243
  end
244
244
 
245
- def assign!(val)
245
+ def assign!(val, src = nil, br = nil)
246
246
  # NOTE: Length of the incomplete array type should be deducted while
247
247
  # initializer evaluation. So, adjustment of the assigning value
248
248
  # can be done at this point by Value#coerce_to(type).
249
249
  # NOTE: Domain of the assigning value must be narrowed before writing to
250
250
  # the memory by Value#coerce_to(type).
251
- binding.memory.write(val.coerce_to(type))
251
+ binding.memory.write(val.coerce_to(type), src, br)
252
252
  end
253
253
 
254
254
  def uninitialize!
@@ -261,7 +261,7 @@ module Cc1 #:nodoc:
261
261
  self.value.narrow_domain!(op, val.coerce_to(type))
262
262
  # NOTE: Write via memory to correctly propagate inner variable's
263
263
  # mutation to its outer variable.
264
- binding.memory._cascade_update
264
+ binding.memory._cascade_update(nil, nil)
265
265
 
266
266
  self.value.exist?
267
267
  end
@@ -272,7 +272,7 @@ module Cc1 #:nodoc:
272
272
  self.value.widen_domain!(op, val.coerce_to(type))
273
273
  # NOTE: Write via memory to correctly propagate inner variable's
274
274
  # mutation to its outer variable.
275
- binding.memory._cascade_update
275
+ binding.memory._cascade_update(nil, nil)
276
276
 
277
277
  self.value.exist?
278
278
  end
@@ -343,15 +343,15 @@ module Cc1 #:nodoc:
343
343
 
344
344
  attr_reader :representative_element
345
345
 
346
- def assign!(val)
346
+ def assign!(val, src = nil, br = nil)
347
347
  super
348
348
  if @representative_element
349
- repr_type = @representative_element.type
350
349
  if val.undefined?
351
- @representative_element.assign!(repr_type.undefined_value)
350
+ repr_val = @representative_element.type.undefined_value
352
351
  else
353
- @representative_element.assign!(repr_type.arbitrary_value)
352
+ repr_val = @representative_element.type.arbitrary_value
354
353
  end
354
+ @representative_element.assign!(repr_val, src, br)
355
355
  end
356
356
  end
357
357
 
@@ -535,6 +535,7 @@ module Cc1 #:nodoc:
535
535
  end
536
536
 
537
537
  Summary = Struct.new(:object_id, :name, :type, :memory)
538
+ private_constant :Summary
538
539
  end
539
540
 
540
541
  class TemporaryVariable < OuterVariable
@@ -559,6 +560,7 @@ module Cc1 #:nodoc:
559
560
  end
560
561
 
561
562
  Summary = Struct.new(:object_id, :type, :memory)
563
+ private_constant :Summary
562
564
  end
563
565
 
564
566
  class InnerVariable < OuterVariable
@@ -686,18 +688,18 @@ module Cc1 #:nodoc:
686
688
  rollback_all_global_variables_value! if current_scope.global?
687
689
  end
688
690
 
689
- def declare(dcl)
691
+ def declare(dcl, br)
690
692
  if var = lookup(dcl.identifier.value)
691
693
  var.declarations_and_definitions.push(dcl)
692
694
  return var
693
695
  end
694
696
 
695
697
  # NOTE: External variable may have undefined values.
696
- define_variable(dcl, dcl.type, allocate_memory(dcl),
698
+ define_variable(dcl, br, dcl.type, allocate_memory(dcl),
697
699
  dcl.type.undefined_value)
698
700
  end
699
701
 
700
- def define(dcl_or_def, init_val = nil)
702
+ def define(dcl_or_def, br, init_val = nil)
701
703
  if storage_duration_of(dcl_or_def) == :static && !dcl_or_def.type.const?
702
704
  # NOTE: Value of the inconstant static duration variable should be
703
705
  # arbitrary because execution of its accessors are out of order.
@@ -720,7 +722,7 @@ module Cc1 #:nodoc:
720
722
 
721
723
  # NOTE: Domain of the init-value will be restricted by type's min-max in
722
724
  # define_variable.
723
- define_variable(dcl_or_def, dcl_or_def.type,
725
+ define_variable(dcl_or_def, br, dcl_or_def.type,
724
726
  allocate_memory(dcl_or_def), init_val)
725
727
  end
726
728
 
@@ -729,7 +731,7 @@ module Cc1 #:nodoc:
729
731
 
730
732
  # NOTE: Domain of the init-value will be restricted by type's min-max in
731
733
  # define_variable.
732
- define_variable(nil, type, mem, init_val)
734
+ define_variable(nil, nil, type, mem, init_val)
733
735
  end
734
736
 
735
737
  def lookup(name_str)
@@ -834,9 +836,9 @@ module Cc1 #:nodoc:
834
836
  end
835
837
 
836
838
  private
837
- def define_variable(dcl_or_def, type, mem, init_val)
839
+ def define_variable(dcl_or_def, br, type, mem, init_val)
838
840
  var = create_variable(dcl_or_def, type, mem)
839
- var.assign!(init_val)
841
+ var.assign!(init_val, dcl_or_def, br)
840
842
 
841
843
  if var.named?
842
844
  @named_variables.last[var.name] = var
@@ -929,8 +931,8 @@ module Cc1 #:nodoc:
929
931
  if type.return_type.function?
930
932
  interp.create_tmpvar
931
933
  else
932
- retn_type = type.return_type
933
- interp.create_tmpvar(retn_type, retn_type.return_value)
934
+ ret_type = type.return_type
935
+ interp.create_tmpvar(ret_type, ret_type.return_value)
934
936
  end
935
937
  end
936
938
 
@@ -994,7 +996,8 @@ module Cc1 #:nodoc:
994
996
  sink = arg
995
997
  end
996
998
 
997
- sink.assign!(sink.type.return_value)
999
+ ret_val = sink.type.return_value
1000
+ sink.assign!(ret_val, funcall_expr, interp.current_branch)
998
1001
  interp.notify_variable_value_updated(expr, sink)
999
1002
 
1000
1003
  # NOTE: Returning a value via a pointer parameter can be considered as
@@ -1173,15 +1176,15 @@ module Cc1 #:nodoc:
1173
1176
  @value
1174
1177
  end
1175
1178
 
1176
- def write(val)
1179
+ def write(val, src, br)
1177
1180
  if @value
1178
- @value.overwrite!(val)
1181
+ @value.overwrite!(val, TransitionTag.new([src], [br]))
1179
1182
  else
1180
- @value = VersionedValue.new(val)
1183
+ @value = VersionedValue.new(val, TransitionTag.new([src], [br]))
1181
1184
  end
1182
1185
  end
1183
1186
 
1184
- def _cascade_update
1187
+ def _cascade_update(src, br)
1185
1188
  # NOTE: This method will be called only from # #narrow_value_domain! and
1186
1189
  # #widen_value_domain! of Variable to propagate memory mutation to
1187
1190
  # the upper MemoryBlock from MemoryWindow.
@@ -1210,12 +1213,12 @@ module Cc1 #:nodoc:
1210
1213
  end
1211
1214
 
1212
1215
  alias :_orig_write :write
1213
- def write(val)
1216
+ def write(val, src, br)
1214
1217
  super
1215
1218
  if !@windows.empty? and
1216
1219
  @value.array? && val.array? or @value.composite? && val.composite?
1217
1220
  @windows.zip(val.to_single_value.values).each do |win, inner_val|
1218
- win.write(inner_val, false)
1221
+ win.write(inner_val, src, br, false)
1219
1222
  end
1220
1223
  end
1221
1224
  end
@@ -1239,12 +1242,12 @@ module Cc1 #:nodoc:
1239
1242
  end
1240
1243
 
1241
1244
  private
1242
- def handle_written_through_window(win)
1245
+ def handle_written_through_window(win, src, br)
1243
1246
  if val = create_value_from_windows
1244
- unless win.read.must_be_undefined?
1247
+ unless win.read.test_must_be_undefined.true?
1245
1248
  val = val.to_defined_value
1246
1249
  end
1247
- _orig_write(val)
1250
+ _orig_write(val, src, br)
1248
1251
  end
1249
1252
  end
1250
1253
  end
@@ -1267,19 +1270,19 @@ module Cc1 #:nodoc:
1267
1270
  @owner.dynamic?
1268
1271
  end
1269
1272
 
1270
- def write(val, cascade = true)
1271
- super(val)
1272
- _cascade_update if cascade
1273
+ def write(val, src, br, cascade = true)
1274
+ super(val, src, br)
1275
+ _cascade_update(src, br) if cascade
1273
1276
  end
1274
1277
 
1275
- def _cascade_update
1276
- on_written.invoke(self)
1278
+ def _cascade_update(src, br)
1279
+ on_written.invoke(self, src, br)
1277
1280
  end
1278
1281
 
1279
1282
  private
1280
- def handle_written_through_window(*)
1283
+ def handle_written_through_window(win, src, br)
1281
1284
  super
1282
- _cascade_update
1285
+ _cascade_update(src, br)
1283
1286
  end
1284
1287
  end
1285
1288
 
@@ -0,0 +1,287 @@
1
+ # Context tracer.
2
+ #
3
+ # Author:: Yutaka Yanoh <mailto:yanoh@users.sourceforge.net>
4
+ # Copyright:: Copyright (C) 2010-2013, OGIS-RI Co.,Ltd.
5
+ # License:: GPLv3+: GNU General Public License version 3 or later
6
+ #
7
+ # Owner:: Yutaka Yanoh <mailto:yanoh@users.sourceforge.net>
8
+
9
+ #--
10
+ # ___ ____ __ ___ _________
11
+ # / | / _ |/ / / / | / /__ __/ Source Code Static Analyzer
12
+ # / /| | / / / / / / / |/ / / / AdLint - Advanced Lint
13
+ # / __ |/ /_/ / /___/ / /| / / /
14
+ # /_/ |_|_____/_____/_/_/ |_/ /_/ Copyright (C) 2010-2013, OGIS-RI Co.,Ltd.
15
+ #
16
+ # This file is part of AdLint.
17
+ #
18
+ # AdLint is free software: you can redistribute it and/or modify it under the
19
+ # terms of the GNU General Public License as published by the Free Software
20
+ # Foundation, either version 3 of the License, or (at your option) any later
21
+ # version.
22
+ #
23
+ # AdLint is distributed in the hope that it will be useful, but WITHOUT ANY
24
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
25
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
26
+ #
27
+ # You should have received a copy of the GNU General Public License along with
28
+ # AdLint. If not, see <http://www.gnu.org/licenses/>.
29
+ #
30
+ #++
31
+
32
+ require "adlint/cc1/branch"
33
+ require "adlint/cc1/value"
34
+
35
+ module AdLint #:nodoc:
36
+ module Cc1 #:nodoc:
37
+
38
+ module ContextTracing
39
+ # NOTE: Host class of this module must respond to #positive_contribs and
40
+ # #negative_contribs.
41
+ def traceable_positive_contribs
42
+ positive_contribs.select { |mval| mval.transition.last.tag.traceable? }
43
+ end
44
+
45
+ def traceable_negative_contribs
46
+ negative_contribs.select { |mval| mval.transition.last.tag.traceable? }
47
+ end
48
+
49
+ def sample_positive_transition
50
+ if contrib = traceable_positive_contribs.first
51
+ contrib.transition
52
+ else
53
+ nil
54
+ end
55
+ end
56
+ end
57
+
58
+ module NegativePathsTracing
59
+ include ContextTracing
60
+
61
+ def trace_negative_paths(report, loc, traced)
62
+ trans = traceable_negative_contribs.map { |mval| mval.transition }
63
+ branches = trans.map { |tr| tr.last.tag.at }.flatten
64
+ sorted_branches = sort_branches_by_groups(branches)
65
+ branches = branches.to_set
66
+
67
+ rch_groups = []
68
+ unr_groups = []
69
+
70
+ sorted_branches.each_key.with_object([]) { |gr, msgs|
71
+ case
72
+ when gr.branches_to_trunk.any? { |upper| branches.include?(upper) }
73
+ next
74
+ when gr.complete? && gr.branches.size == sorted_branches[gr].size
75
+ unr_groups.push(gr)
76
+ else
77
+ rch_groups.push(gr)
78
+ sorted_branches[gr].each do |br|
79
+ emit_negative_ctrlexpr(msgs, report, loc, traced, br.ctrlexpr)
80
+ end
81
+ end
82
+ } + emit_remaining_paths(report, loc, traced, rch_groups, unr_groups)
83
+ end
84
+
85
+ private
86
+ def emit_remaining_paths(report, loc, traced, rch_groups, unr_groups)
87
+ traced_groups = Set.new
88
+ rch_groups.each_with_object([]) { |gr, msgs|
89
+ cur_br = gr.trunk
90
+ while cur_br
91
+ emit_positive_ctrlexpr(msgs, report, loc, traced, cur_br.ctrlexpr)
92
+ traced_groups.add(cur_br.group)
93
+ cur_br = cur_br.trunk
94
+ end
95
+ } + unr_groups.each_with_object([]) { |gr, msgs|
96
+ cur_br = gr.trunk
97
+ while cur_br
98
+ unless traced_groups.include?(cur_br.group)
99
+ emit_negative_ctrlexpr(msgs, report, loc, traced, cur_br.ctrlexpr)
100
+ break
101
+ end
102
+ cur_br = cur_br.trunk
103
+ end
104
+ }
105
+ end
106
+
107
+ def sort_branches_by_groups(branches)
108
+ branches.each_with_object(Hash.new { |h, k| h[k] = [] }) do |br, groups|
109
+ groups[br.group].push(br)
110
+ end
111
+ end
112
+
113
+ def emit_positive_ctrlexpr(msgs, report, loc, traced, ctrlexpr)
114
+ if ctrlexpr and expr = ctrlexpr.to_expr
115
+ if expr.location && expr.location < loc && !traced.include?(expr)
116
+ msgs.push(report.C(:C1001, expr.location))
117
+ traced.add(expr)
118
+ end
119
+ end
120
+ end
121
+
122
+ def emit_negative_ctrlexpr(msgs, report, loc, traced, ctrlexpr)
123
+ if ctrlexpr and expr = ctrlexpr.to_expr
124
+ if expr.location && expr.location < loc && !traced.include?(expr)
125
+ msgs.push(report.C(:C1002, expr.location))
126
+ traced.add(expr)
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ module UndefinableContextTracing
133
+ include ContextTracing
134
+ include NegativePathsTracing
135
+
136
+ def emit_context_messages(report, loc)
137
+ traced = Set.new
138
+ msgs = trace_positive_paths(report, loc, traced) +
139
+ trace_negative_paths(report, loc, traced)
140
+
141
+ unless msgs.empty?
142
+ [report.C(:C1000, Location.new)] +
143
+ msgs.sort { |a, b| a.location <=> b.location }
144
+ else
145
+ []
146
+ end
147
+ end
148
+
149
+ private
150
+ def trace_positive_paths(report, loc, traced)
151
+ # TODO: Evidence of the test result might have two or more contributors.
152
+ # All the evidences should be complemented by context messages?
153
+ unless pos_trans = sample_positive_transition
154
+ return []
155
+ end
156
+
157
+ pos_trans.each_with_object([]) do |ss, msgs|
158
+ if src = ss.tag.by.find { |node| node.kind_of?(VariableDefinition) }
159
+ if src.location && src.location < loc && !traced.include?(src)
160
+ if ss.value.test_may_be_undefined.true?
161
+ msgs.push(report.C(:C1003, src.location))
162
+ traced.add(src)
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ # NOTE: Mix-in this module to AdLint::Cc1::UndefinableTestEvidence.
170
+ UndefinableTestEvidence.class_eval { include UndefinableContextTracing }
171
+ end
172
+
173
+ module NullabilityContextTracing
174
+ include ContextTracing
175
+ include NegativePathsTracing
176
+
177
+ def emit_context_messages(report, loc)
178
+ traced = Set.new
179
+ msgs = trace_positive_paths(report, loc, traced) +
180
+ trace_negative_paths(report, loc, traced)
181
+
182
+ unless msgs.empty?
183
+ [report.C(:C1000, Location.new)] +
184
+ msgs.sort { |a, b| a.location <=> b.location }
185
+ else
186
+ []
187
+ end
188
+ end
189
+
190
+ private
191
+ def trace_positive_paths(report, loc, traced)
192
+ # TODO: Evidence of the test result might have two or more contributors.
193
+ # All the evidences should be complemented by context messages?
194
+ unless pos_trans = sample_positive_transition
195
+ return []
196
+ end
197
+
198
+ pos_trans.each_with_object([]) do |ss, msgs|
199
+ branch = ss.tag.at.find { |br| br.ctrlexpr.to_expr }
200
+ while branch
201
+ if expr = branch.ctrlexpr.to_expr and
202
+ expr.location && expr.location < loc
203
+ unless traced.include?(expr)
204
+ msgs.push(report.C(:C1001, expr.location))
205
+ traced.add(expr)
206
+ end
207
+ end
208
+ branch = branch.trunk
209
+ end
210
+
211
+ src = ss.tag.by.find { |node|
212
+ node.location && node.location < loc && !traced.include?(node)
213
+ }
214
+ if src
215
+ case
216
+ when ss.value.test_must_be_null.true?
217
+ msgs.push(report.C(:C1004, src.location))
218
+ traced.add(src)
219
+ when ss.value.test_may_be_null.true?
220
+ msgs.push(report.C(:C1005, src.location))
221
+ traced.add(src)
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ # NOTE: Mix-in this module to AdLint::Cc1::NullabilityTestEvidence.
228
+ NullabilityTestEvidence.class_eval { include NullabilityContextTracing }
229
+ end
230
+
231
+ module DefinableContextTracing
232
+ # NOTE: Host class must have instance variable named @predicate.
233
+ attr_reader :predicate
234
+
235
+ include ContextTracing
236
+ include NegativePathsTracing
237
+
238
+ def emit_context_messages(report, loc)
239
+ traced = Set.new
240
+ msgs = trace_positive_paths(report, loc, traced) +
241
+ trace_negative_paths(report, loc, traced)
242
+
243
+ unless msgs.empty?
244
+ [report.C(:C1000, Location.new)] +
245
+ msgs.sort { |a, b| a.location <=> b.location }
246
+ else
247
+ []
248
+ end
249
+ end
250
+
251
+ private
252
+ def trace_positive_paths(report, loc, traced)
253
+ # TODO: Evidence of the test result might have two or more contributors.
254
+ # All the evidences should be complemented by context messages?
255
+ unless pos_trans = sample_positive_transition
256
+ return []
257
+ end
258
+
259
+ pos_trans.each_with_object([]) do |ss, msgs|
260
+ branch = ss.tag.at.find { |br| br.ctrlexpr.to_expr }
261
+ while branch
262
+ if expr = branch.ctrlexpr.to_expr and
263
+ expr.location && expr.location < loc
264
+ unless traced.include?(expr)
265
+ msgs.push(report.C(:C1001, expr.location))
266
+ traced.add(expr)
267
+ end
268
+ end
269
+ branch = branch.trunk
270
+ end
271
+
272
+ src = ss.tag.by.find { |node|
273
+ node.location && node.location < loc && !traced.include?(node)
274
+ }
275
+ if src && predicate.call(ss.value)
276
+ msgs.push(report.C(:C1006, src.location))
277
+ traced.add(src)
278
+ end
279
+ end
280
+ end
281
+
282
+ # NOTE: Mix-in this module to AdLint::Cc1::DefinableTestEvidence.
283
+ DefinableTestEvidence.class_eval { include DefinableContextTracing }
284
+ end
285
+
286
+ end
287
+ end