adlint 3.0.10 → 3.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 (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