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.
- 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
|