adlint 3.0.10 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +67 -0
- data/MANIFEST +2 -0
- data/NEWS +10 -3
- data/etc/mesg.d/c_builtin/en_US/messages.yml +29 -1
- data/etc/mesg.d/c_builtin/ja_JP/messages.yml +29 -1
- data/etc/mesg.d/core/en_US/messages.yml +1 -1
- data/etc/mesg.d/core/ja_JP/messages.yml +1 -1
- data/features/code_check/W0003.feature +5 -0
- data/features/code_check/W0023.feature +32 -0
- data/features/code_check/W0024.feature +22 -0
- data/features/code_check/W0093.feature +71 -0
- data/features/code_check/W0097.feature +4 -0
- data/features/code_check/W0100.feature +10 -0
- data/features/code_check/W0119.feature +8 -0
- data/features/code_check/W0133.feature +8 -0
- data/features/code_check/W0134.feature +8 -0
- data/features/code_check/W0136.feature +8 -0
- data/features/code_check/W0138.feature +8 -0
- data/features/code_check/W0140.feature +8 -0
- data/features/code_check/W0142.feature +8 -0
- data/features/code_check/W0143.feature +8 -0
- data/features/code_check/W0144.feature +8 -0
- data/features/code_check/W0145.feature +8 -0
- data/features/code_check/W0146.feature +8 -0
- data/features/code_check/W0147.feature +8 -0
- data/features/code_check/W0148.feature +8 -0
- data/features/code_check/W0149.feature +8 -0
- data/features/code_check/W0150.feature +8 -0
- data/features/code_check/W0151.feature +8 -0
- data/features/code_check/W0152.feature +8 -0
- data/features/code_check/W0153.feature +8 -0
- data/features/code_check/W0154.feature +8 -0
- data/features/code_check/W0155.feature +8 -0
- data/features/code_check/W0156.feature +8 -0
- data/features/code_check/W0157.feature +8 -0
- data/features/code_check/W0158.feature +8 -0
- data/features/code_check/W0159.feature +8 -0
- data/features/code_check/W0160.feature +8 -0
- data/features/code_check/W0161.feature +8 -0
- data/features/code_check/W0162.feature +8 -0
- data/features/code_check/W0163.feature +8 -0
- data/features/code_check/W0164.feature +8 -0
- data/features/code_check/W0165.feature +8 -0
- data/features/code_check/W0166.feature +8 -0
- data/features/code_check/W0167.feature +8 -0
- data/features/code_check/W0168.feature +8 -0
- data/features/code_check/W0169.feature +8 -0
- data/features/code_check/W0170.feature +8 -0
- data/features/code_check/W0171.feature +8 -0
- data/features/code_check/W0172.feature +8 -0
- data/features/code_check/W0173.feature +8 -0
- data/features/code_check/W0174.feature +8 -0
- data/features/code_check/W0175.feature +8 -0
- data/features/code_check/W0176.feature +8 -0
- data/features/code_check/W0177.feature +8 -0
- data/features/code_check/W0178.feature +8 -0
- data/features/code_check/W0179.feature +8 -0
- data/features/code_check/W0180.feature +8 -0
- data/features/code_check/W0181.feature +8 -0
- data/features/code_check/W0250.feature +8 -0
- data/features/code_check/W0422.feature +194 -0
- data/features/code_check/W0459.feature +16 -0
- data/features/code_check/W0460.feature +342 -0
- data/features/code_check/W0461.feature +5 -0
- data/features/code_check/W0497.feature +12 -0
- data/features/code_check/W0499.feature +6 -0
- data/features/code_check/W0502.feature +6 -0
- data/features/code_check/W0570.feature +47 -0
- data/features/code_check/W0573.feature +8 -0
- data/features/code_check/W0582.feature +4 -0
- data/features/code_check/W0583.feature +4 -0
- data/features/code_check/W0584.feature +10 -0
- data/features/code_check/W0599.feature +10 -0
- data/features/code_check/W0644.feature +2 -0
- data/features/code_check/W0649.feature +14 -0
- data/features/code_check/W0650.feature +12 -0
- data/features/code_check/W0685.feature +10 -0
- data/features/code_check/W0686.feature +8 -0
- data/features/code_check/W0711.feature +2 -0
- data/features/code_check/W0712.feature +2 -0
- data/features/code_check/W0713.feature +2 -0
- data/features/code_check/W0714.feature +2 -0
- data/features/code_check/W0715.feature +2 -0
- data/features/code_check/W0718.feature +2 -0
- data/features/code_check/W0719.feature +8 -0
- data/features/code_check/W0732.feature +18 -0
- data/features/code_check/W0733.feature +18 -0
- data/features/code_check/W0734.feature +24 -0
- data/features/code_check/W0735.feature +24 -0
- data/features/code_check/W0747.feature +8 -0
- data/features/code_check/W0749.feature +8 -0
- data/features/code_check/W0750.feature +8 -0
- data/features/code_check/W0753.feature +8 -0
- data/features/code_check/W0754.feature +8 -0
- data/features/code_check/W0759.feature +8 -0
- data/features/code_check/W0760.feature +8 -0
- data/features/code_check/W0761.feature +8 -0
- data/features/code_check/W0762.feature +8 -0
- data/features/code_check/W0794.feature +6 -0
- data/features/code_check/W1050.feature +8 -0
- data/features/code_check/W1066.feature +8 -0
- data/features/code_check/W1067.feature +8 -0
- data/features/code_check/W1068.feature +8 -0
- data/features/code_check/W1071.feature +4 -0
- data/features/code_check/W9003.feature +2 -0
- data/lib/adlint/cc1.rb +1 -0
- data/lib/adlint/cc1/branch.rb +34 -13
- data/lib/adlint/cc1/conv.rb +3 -3
- data/lib/adlint/cc1/ctrlexpr.rb +12 -7
- data/lib/adlint/cc1/environ.rb +12 -2
- data/lib/adlint/cc1/expr.rb +10 -8
- data/lib/adlint/cc1/interp.rb +56 -49
- data/lib/adlint/cc1/mediator.rb +9 -5
- data/lib/adlint/cc1/object.rb +37 -34
- data/lib/adlint/cc1/trace.rb +287 -0
- data/lib/adlint/cc1/type.rb +15 -15
- data/lib/adlint/cc1/value.rb +823 -427
- data/lib/adlint/cpp/eval.rb +5 -2
- data/lib/adlint/cpp/source.rb +21 -22
- data/lib/adlint/exam/c_builtin/cc1_check.rb +1636 -1067
- data/lib/adlint/exam/c_builtin/cc1_check_shima.rb +28 -22
- data/lib/adlint/exam/c_builtin/cc1_code.rb +4 -4
- data/lib/adlint/exam/c_builtin/cc1_metric.rb +14 -14
- data/lib/adlint/location.rb +5 -7
- data/lib/adlint/metric.rb +2 -2
- data/lib/adlint/prelude.rb +6 -2
- data/lib/adlint/report.rb +2 -2
- data/lib/adlint/version.rb +3 -3
- data/share/doc/developers_guide_ja.html +10 -4
- data/share/doc/developers_guide_ja.texi +8 -2
- data/share/doc/users_guide_en.html +679 -72
- data/share/doc/users_guide_en.texi +557 -12
- data/share/doc/users_guide_ja.html +678 -74
- data/share/doc/users_guide_ja.texi +554 -13
- data/spec/adlint/cc1/ctrlexpr_spec.rb +20 -11
- data/spec/adlint/cc1/domain_spec.rb +9 -0
- metadata +4 -2
data/lib/adlint/cc1/object.rb
CHANGED
@@ -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.
|
350
|
+
repr_val = @representative_element.type.undefined_value
|
352
351
|
else
|
353
|
-
@representative_element.
|
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
|
-
|
933
|
-
interp.create_tmpvar(
|
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.
|
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.
|
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
|