adlint 1.16.0 → 1.18.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 +471 -0
- data/MANIFEST +35 -8
- data/NEWS +50 -4
- data/bin/adlint +7 -7
- data/bin/adlint_chk +7 -7
- data/bin/adlint_cma +7 -7
- data/bin/adlint_sma +7 -7
- data/bin/adlintize +5 -5
- data/etc/mesg.d/en_US/messages.yml +3 -3
- data/etc/mesg.d/ja_JP/messages.yml +3 -3
- data/features/message_detection/E0013.feature +34 -0
- data/features/message_detection/W0007.feature +2 -0
- data/features/message_detection/W0583.feature +1 -2
- data/features/message_detection/W0641.feature +132 -0
- data/features/message_detection/W0643.feature +1 -1
- data/features/message_detection/W0644.feature +529 -0
- data/features/message_detection/W0645.feature +1 -1
- data/features/message_detection/W0649.feature +277 -0
- data/features/message_detection/W0650.feature +208 -0
- data/features/message_detection/W0697.feature +6 -0
- data/features/message_detection/W0705.feature +350 -0
- data/features/message_detection/W0707.feature +223 -0
- data/features/message_detection/W0711.feature +113 -0
- data/features/message_detection/W0712.feature +113 -0
- data/features/message_detection/W0713.feature +110 -0
- data/features/message_detection/W0714.feature +118 -0
- data/features/message_detection/W0715.feature +118 -0
- data/features/message_detection/W0716.feature +1 -0
- data/features/message_detection/W0717.feature +1 -0
- data/features/message_detection/W0718.feature +1 -0
- data/features/message_detection/W0719.feature +154 -0
- data/features/message_detection/W0723.feature +1 -2
- data/features/message_detection/W0732.feature +3 -0
- data/features/message_detection/W0733.feature +3 -0
- data/features/message_detection/W0734.feature +4 -0
- data/features/message_detection/W0735.feature +4 -0
- data/features/message_detection/W0745.feature +132 -0
- data/features/message_detection/W0780.feature +68 -0
- data/features/message_detection/W0783.feature +95 -0
- data/features/message_detection/W0792.feature +124 -0
- data/features/message_detection/W0793.feature +153 -0
- data/features/message_detection/W0794.feature +90 -0
- data/features/message_detection/W0830.feature +65 -0
- data/features/message_detection/W0833.feature +220 -0
- data/features/message_detection/W0834.feature +189 -0
- data/features/message_detection/W1026.feature +105 -0
- data/features/message_detection/W1031.feature +17 -34
- data/features/message_detection/W1039.feature +268 -0
- data/features/message_detection/W1047.feature +163 -0
- data/features/message_detection/W1066.feature +1 -0
- data/features/message_detection/W1067.feature +1 -0
- data/features/message_detection/W1068.feature +1 -0
- data/features/message_detection/W1069.feature +5 -0
- data/features/message_detection/W1070.feature +5 -0
- data/features/message_detection/W1071.feature +83 -0
- data/features/message_detection/W1073.feature +3 -2
- data/features/message_detection/W9003.feature +7 -12
- data/features/step_definitions/message_detection_steps.rb +4 -31
- data/features/support/env.rb +117 -2
- data/lib/adlint/c/branch.rb +0 -2
- data/lib/adlint/c/ctrlexpr.rb +33 -0
- data/lib/adlint/c/expr.rb +119 -31
- data/lib/adlint/c/interp.rb +44 -3
- data/lib/adlint/c/message.rb +1411 -29
- data/lib/adlint/c/object.rb +16 -2
- data/lib/adlint/c/option.rb +1 -0
- data/lib/adlint/c/parser.rb +101 -100
- data/lib/adlint/c/parser.y +3 -2
- data/lib/adlint/c/phase.rb +18 -0
- data/lib/adlint/c/resolver.rb +23 -0
- data/lib/adlint/c/syntax.rb +90 -4
- data/lib/adlint/c/type.rb +177 -110
- data/lib/adlint/cpp/macro.rb +4 -4
- data/lib/adlint/version.rb +2 -2
- data/share/demo/bad_include/test/"1/".h +0 -0
- data/share/doc/developers_guide_ja.html +3 -3
- data/share/doc/developers_guide_ja.texi +1 -1
- data/share/doc/users_guide_en.html +467 -506
- data/share/doc/users_guide_en.texi +95 -125
- data/share/doc/users_guide_ja.html +471 -518
- data/share/doc/users_guide_ja.texi +95 -133
- data/spec/spec_helper.rb +6 -0
- metadata +37 -10
data/lib/adlint/c/interp.rb
CHANGED
@@ -71,6 +71,7 @@ module C #:nodoc:
|
|
71
71
|
include InterpreterMediator
|
72
72
|
include Conversion
|
73
73
|
include InterpreterOptions
|
74
|
+
include BranchOptions
|
74
75
|
|
75
76
|
def initialize(type_table)
|
76
77
|
type_table = type_table
|
@@ -426,7 +427,17 @@ module C #:nodoc:
|
|
426
427
|
|
427
428
|
def execute(node, *options)
|
428
429
|
@options_stack.push(current_options + options)
|
429
|
-
|
430
|
+
if quiet_without_side_effect?
|
431
|
+
result = nil
|
432
|
+
branched_eval(nil, FINAL) do
|
433
|
+
result = node.accept(interpreter_for(node))
|
434
|
+
# NOTE: To rollback latest variable value versions.
|
435
|
+
BreakEvent.of_return.throw
|
436
|
+
end
|
437
|
+
else
|
438
|
+
result = node.accept(interpreter_for(node))
|
439
|
+
end
|
440
|
+
result
|
430
441
|
ensure
|
431
442
|
@options_stack.pop
|
432
443
|
end
|
@@ -456,7 +467,8 @@ module C #:nodoc:
|
|
456
467
|
end
|
457
468
|
|
458
469
|
def quiet?
|
459
|
-
current_options.include?(QUIET)
|
470
|
+
current_options.include?(QUIET) ||
|
471
|
+
current_options.include?(QUIET_WITHOUT_SIDE_EFFECT)
|
460
472
|
end
|
461
473
|
|
462
474
|
def _quiet=(quiet)
|
@@ -468,6 +480,10 @@ module C #:nodoc:
|
|
468
480
|
end
|
469
481
|
end
|
470
482
|
|
483
|
+
def quiet_without_side_effect?
|
484
|
+
current_options.include?(QUIET_WITHOUT_SIDE_EFFECT)
|
485
|
+
end
|
486
|
+
|
471
487
|
def _active_function
|
472
488
|
# NOTE: This method is called only from
|
473
489
|
# StatementInterpreter#visit_return_statement.
|
@@ -726,11 +742,36 @@ module C #:nodoc:
|
|
726
742
|
end
|
727
743
|
|
728
744
|
def evaluate_initializers(initializers, variable_type)
|
745
|
+
# NOTE: The ISO C99 standard saids;
|
746
|
+
#
|
747
|
+
# 6.7.8 Initialization
|
748
|
+
#
|
749
|
+
# Semantics
|
750
|
+
#
|
751
|
+
# 10 If an object that has automatic storage duration is not initialized
|
752
|
+
# explicitly, its value is indeterminate. If an object that has
|
753
|
+
# static storage duration is not initialized explicitly, then:
|
754
|
+
# -- if it has pointer type, it is initialized to a null pointer;
|
755
|
+
# -- if it has arithmetic type, it is initialized to (positive or
|
756
|
+
# unsigned) zero;
|
757
|
+
# -- if it is an aggregate, every member is initialized (recursively)
|
758
|
+
# according to these rules;
|
759
|
+
# -- if it is a union, the first named member is initialized
|
760
|
+
# (recursively) according to these rules.
|
761
|
+
if variable_type.union?
|
762
|
+
if first_member = variable_type.members.first
|
763
|
+
first_object = evaluate_initializers(initializers, first_member.type)
|
764
|
+
return temporary_variable(variable_type, value_of(first_object))
|
765
|
+
else
|
766
|
+
return temporary_variable(variable_type)
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
729
770
|
case
|
730
771
|
when variable_type.array?
|
731
772
|
deduct_array_length_from_initializers(variable_type, initializers)
|
732
773
|
member_types = [variable_type.base_type] * variable_type.impl_length
|
733
|
-
when variable_type.
|
774
|
+
when variable_type.struct?
|
734
775
|
member_types = variable_type.members.map { |member| member.type }
|
735
776
|
else
|
736
777
|
member_types = [variable_type]
|
data/lib/adlint/c/message.rb
CHANGED
@@ -31,9 +31,11 @@
|
|
31
31
|
|
32
32
|
require "adlint/report"
|
33
33
|
require "adlint/message"
|
34
|
+
require "adlint/token"
|
34
35
|
require "adlint/traits"
|
35
36
|
require "adlint/monitor"
|
36
37
|
require "adlint/c/syntax"
|
38
|
+
require "adlint/c/type"
|
37
39
|
require "adlint/c/format"
|
38
40
|
require "adlint/c/option"
|
39
41
|
require "adlint/c/util"
|
@@ -1832,7 +1834,7 @@ module C #:nodoc:
|
|
1832
1834
|
end
|
1833
1835
|
|
1834
1836
|
def write_variable(expression, variable)
|
1835
|
-
variable = variable.owner while variable.
|
1837
|
+
variable = variable.owner while variable.inner?
|
1836
1838
|
return unless variable.named?
|
1837
1839
|
|
1838
1840
|
@variable_stack.reverse_each do |variables|
|
@@ -6933,6 +6935,7 @@ module C #:nodoc:
|
|
6933
6935
|
return if variable.scope.global? || variable.binding.memory.static?
|
6934
6936
|
|
6935
6937
|
if variable.named? && variable.value.must_be_undefined?
|
6938
|
+
variable = variable.owner while variable.inner?
|
6936
6939
|
W(:W0459, expression.location, variable.name)
|
6937
6940
|
end
|
6938
6941
|
end
|
@@ -11539,6 +11542,29 @@ module C #:nodoc:
|
|
11539
11542
|
end
|
11540
11543
|
end
|
11541
11544
|
|
11545
|
+
class W0641 < PassiveMessageDetection
|
11546
|
+
def initialize(context)
|
11547
|
+
super
|
11548
|
+
interp = context[:c_interpreter]
|
11549
|
+
interp.on_explicit_conv_performed += method(:check)
|
11550
|
+
end
|
11551
|
+
|
11552
|
+
private
|
11553
|
+
def check(expression, original_variable, result_variable)
|
11554
|
+
lhs_type = original_variable.type.unqualify
|
11555
|
+
rhs_type = result_variable.type.unqualify
|
11556
|
+
|
11557
|
+
case
|
11558
|
+
when lhs_type.floating? &&
|
11559
|
+
rhs_type.pointer? && !rhs_type.base_type.function?
|
11560
|
+
W(:W0641, expression.location)
|
11561
|
+
when rhs_type.floating? &&
|
11562
|
+
lhs_type.pointer? && !lhs_type.base_type.function?
|
11563
|
+
W(:W0641, expression.location)
|
11564
|
+
end
|
11565
|
+
end
|
11566
|
+
end
|
11567
|
+
|
11542
11568
|
class W0642 < PassiveMessageDetection
|
11543
11569
|
def initialize(context)
|
11544
11570
|
super
|
@@ -11561,6 +11587,27 @@ module C #:nodoc:
|
|
11561
11587
|
end
|
11562
11588
|
end
|
11563
11589
|
|
11590
|
+
class W0644 < PassiveMessageDetection
|
11591
|
+
# NOTE: W0644 may be duplicative when both hand side of a binary-expression
|
11592
|
+
# refer a value of `void' expression.
|
11593
|
+
ensure_uniqueness_of :W0644
|
11594
|
+
|
11595
|
+
def initialize(context)
|
11596
|
+
super
|
11597
|
+
interp = context[:c_interpreter]
|
11598
|
+
|
11599
|
+
interp.on_variable_value_referred += method(:check)
|
11600
|
+
interp.on_explicit_conv_performed += lambda { |expr, from, to|
|
11601
|
+
check(expr, from)
|
11602
|
+
}
|
11603
|
+
end
|
11604
|
+
|
11605
|
+
private
|
11606
|
+
def check(expression, variable)
|
11607
|
+
W(:W0644, expression.location) if variable.type.void?
|
11608
|
+
end
|
11609
|
+
end
|
11610
|
+
|
11564
11611
|
class W0646 < PassiveMessageDetection
|
11565
11612
|
def initialize(context)
|
11566
11613
|
super
|
@@ -11577,6 +11624,45 @@ module C #:nodoc:
|
|
11577
11624
|
end
|
11578
11625
|
end
|
11579
11626
|
|
11627
|
+
class W0649 < PassiveMessageDetection
|
11628
|
+
def initialize(context)
|
11629
|
+
super
|
11630
|
+
interp = context[:c_interpreter]
|
11631
|
+
interp.on_shift_expr_evaled += method(:check)
|
11632
|
+
@enum_tbl = interp.environment.enumerator_table
|
11633
|
+
end
|
11634
|
+
|
11635
|
+
private
|
11636
|
+
def check(expr, lhs_variable, rhs_variable, result_variable)
|
11637
|
+
if expr.rhs_operand.constant?(@enum_tbl)
|
11638
|
+
if rhs_variable.value.must_be_less_than?(ScalarValue.of(0))
|
11639
|
+
W(:W0649, expr.location)
|
11640
|
+
end
|
11641
|
+
end
|
11642
|
+
end
|
11643
|
+
end
|
11644
|
+
|
11645
|
+
class W0650 < PassiveMessageDetection
|
11646
|
+
def initialize(context)
|
11647
|
+
super
|
11648
|
+
interp = context[:c_interpreter]
|
11649
|
+
interp.on_shift_expr_evaled += method(:check)
|
11650
|
+
@enum_tbl = interp.environment.enumerator_table
|
11651
|
+
end
|
11652
|
+
|
11653
|
+
private
|
11654
|
+
def check(expr, lhs_variable, rhs_variable, result_variable)
|
11655
|
+
if expr.rhs_operand.constant?(@enum_tbl)
|
11656
|
+
promoted_type = lhs_variable.type.integer_promoted_type
|
11657
|
+
promoted_bit_size = ScalarValue.of(promoted_type.bit_size)
|
11658
|
+
if rhs_variable.value.must_be_equal_to?(promoted_bit_size) ||
|
11659
|
+
rhs_variable.value.must_be_greater_than?(promoted_bit_size)
|
11660
|
+
W(:W0650, expr.location)
|
11661
|
+
end
|
11662
|
+
end
|
11663
|
+
end
|
11664
|
+
end
|
11665
|
+
|
11580
11666
|
class W0653 < PassiveMessageDetection
|
11581
11667
|
def initialize(context)
|
11582
11668
|
super
|
@@ -12314,30 +12400,624 @@ module C #:nodoc:
|
|
12314
12400
|
end
|
12315
12401
|
|
12316
12402
|
class W0705 < PassiveMessageDetection
|
12403
|
+
include SyntaxNodeCollector
|
12404
|
+
include InterpreterOptions
|
12405
|
+
|
12317
12406
|
def initialize(context)
|
12318
12407
|
super
|
12319
|
-
interp = context[:c_interpreter]
|
12320
|
-
interp.on_array_subscript_expr_evaled += method(:
|
12408
|
+
@interp = context[:c_interpreter]
|
12409
|
+
@interp.on_array_subscript_expr_evaled += method(:check_array_subscript)
|
12410
|
+
@interp.on_indirection_expr_evaled += method(:check_indirection)
|
12411
|
+
@enum_tbl = @interp.environment.enumerator_table
|
12321
12412
|
end
|
12322
12413
|
|
12323
12414
|
private
|
12324
|
-
def
|
12325
|
-
|
12326
|
-
array_variable, result_variable)
|
12327
|
-
return unless array_variable && array_variable.type.length
|
12328
|
-
return unless subscript_variable.value.scalar?
|
12415
|
+
def check_array_subscript(expression, *, subscript, array, result)
|
12416
|
+
return unless array
|
12329
12417
|
|
12330
|
-
|
12331
|
-
|
12418
|
+
unless expression.array_subscript.constant?(@enum_tbl)
|
12419
|
+
warn_array_oob_access(expression.array_subscript, array, subscript)
|
12420
|
+
end
|
12421
|
+
end
|
12332
12422
|
|
12333
|
-
|
12334
|
-
|
12423
|
+
def check_indirection(expression, *)
|
12424
|
+
array, subscript_expr = extract_array_and_subscript(expression.operand)
|
12425
|
+
return unless array
|
12335
12426
|
|
12336
|
-
|
12337
|
-
|
12338
|
-
|
12427
|
+
unless subscript_expr.constant?(@enum_tbl)
|
12428
|
+
subscript = @interp.interpret(subscript_expr,
|
12429
|
+
QUIET_WITHOUT_SIDE_EFFECT)
|
12430
|
+
warn_array_oob_access(expression.operand, array, subscript)
|
12431
|
+
end
|
12432
|
+
end
|
12433
|
+
|
12434
|
+
def warn_array_oob_access(expression, array, subscript)
|
12435
|
+
if array_length = array.type.length
|
12436
|
+
lower_bound = ScalarValue.of(0)
|
12437
|
+
upper_bound = ScalarValue.of(array_length - 1)
|
12438
|
+
|
12439
|
+
lower_test = subscript.value < lower_bound
|
12440
|
+
upper_test = subscript.value > upper_bound
|
12441
|
+
|
12442
|
+
if !lower_test.must_be_true? && lower_test.may_be_true? or
|
12443
|
+
!upper_test.must_be_true? && upper_test.may_be_true?
|
12444
|
+
W(:W0705, expression.location)
|
12445
|
+
end
|
12446
|
+
end
|
12447
|
+
end
|
12448
|
+
|
12449
|
+
def extract_array_and_subscript(expression)
|
12450
|
+
array, array_name = extract_array(expression)
|
12451
|
+
subscript_expr = create_subscript_expr(expression, array_name)
|
12452
|
+
return array, subscript_expr
|
12453
|
+
end
|
12454
|
+
|
12455
|
+
def extract_array(expression)
|
12456
|
+
collect_object_specifiers(expression).each do |os|
|
12457
|
+
if object = @interp.variable_named(os.identifier.value)
|
12458
|
+
case
|
12459
|
+
when object.type.array?
|
12460
|
+
return object, os.identifier.value
|
12461
|
+
when object.type.pointer?
|
12462
|
+
if object = @interp.pointee_of(object) and object.type.array?
|
12463
|
+
return object, os.identifier.value
|
12464
|
+
end
|
12465
|
+
end
|
12466
|
+
end
|
12467
|
+
end
|
12468
|
+
nil
|
12469
|
+
end
|
12470
|
+
|
12471
|
+
def create_subscript_expr(expression, array_name)
|
12472
|
+
expression.accept(ExpressionTransformer.new(array_name))
|
12473
|
+
end
|
12474
|
+
|
12475
|
+
class ExpressionTransformer < SyntaxTreeVisitor
|
12476
|
+
def initialize(array_name)
|
12477
|
+
@array_name = array_name
|
12478
|
+
end
|
12479
|
+
|
12480
|
+
def visit_error_expression(node)
|
12481
|
+
node
|
12482
|
+
end
|
12483
|
+
|
12484
|
+
def visit_object_specifier(node)
|
12485
|
+
if node.identifier.value == @array_name
|
12486
|
+
ConstantSpecifier.new(Token.new(:CONSTANT, "0", node.location))
|
12487
|
+
else
|
12488
|
+
node
|
12489
|
+
end
|
12490
|
+
end
|
12491
|
+
|
12492
|
+
def visit_constant_specifier(node)
|
12493
|
+
node
|
12494
|
+
end
|
12495
|
+
|
12496
|
+
def visit_string_literal_specifier(node)
|
12497
|
+
node
|
12498
|
+
end
|
12499
|
+
|
12500
|
+
def visit_null_constant_specifier(node)
|
12501
|
+
node
|
12502
|
+
end
|
12503
|
+
|
12504
|
+
def visit_grouped_expression(node)
|
12505
|
+
GroupedExpression.new(node.expression.accept(self))
|
12506
|
+
end
|
12507
|
+
|
12508
|
+
def visit_array_subscript_expression(node)
|
12509
|
+
ArraySubscriptExpression.new(node.expression.accept(self),
|
12510
|
+
node.array_subscript.accept(self),
|
12511
|
+
node.operator)
|
12512
|
+
end
|
12513
|
+
|
12514
|
+
def visit_function_call_expression(node)
|
12515
|
+
FunctionCallExpression.new(
|
12516
|
+
node.expression.accept(self),
|
12517
|
+
node.argument_expressions.map { |expr| expr.accept(self) },
|
12518
|
+
node.operator)
|
12519
|
+
end
|
12520
|
+
|
12521
|
+
def visit_member_access_by_value_expression(node)
|
12522
|
+
MemberAccessByValueExpression.new(node.expression.accept(self),
|
12523
|
+
node.identifier, node.operator)
|
12524
|
+
end
|
12525
|
+
|
12526
|
+
def visit_member_access_by_pointer_expression(node)
|
12527
|
+
MemberAccessByPointerExpression.new(node.expression.accept(self),
|
12528
|
+
node.identifier, node.operator)
|
12529
|
+
end
|
12530
|
+
|
12531
|
+
def visit_bit_access_by_value_expression(node)
|
12532
|
+
BitAccessByValueExpression.new(node.expression.accept(self),
|
12533
|
+
node.constant, node.operator)
|
12534
|
+
end
|
12535
|
+
|
12536
|
+
def visit_bit_access_by_pointer_expression(node)
|
12537
|
+
BitAccessByPointerExpression.new(node.expression.accept(self),
|
12538
|
+
node.constant, node.operator)
|
12539
|
+
end
|
12540
|
+
|
12541
|
+
def visit_postfix_increment_expression(node)
|
12542
|
+
# NOTE: The postfix-increment-expression is already evaluated with
|
12543
|
+
# side-effect.
|
12544
|
+
# To rollback the side-effect, create an inverted expression.
|
12545
|
+
PrefixDecrementExpression.new(
|
12546
|
+
Token.new("--", "--", node.operator.location),
|
12547
|
+
node.operand.accept(self))
|
12548
|
+
end
|
12549
|
+
|
12550
|
+
def visit_postfix_decrement_expression(node)
|
12551
|
+
# NOTE: The postfix-decrement-expression is already evaluated with
|
12552
|
+
# side-effect.
|
12553
|
+
# To rollback the side-effect, create an inverted expression.
|
12554
|
+
PrefixIncrementExpression.new(
|
12555
|
+
Token.new("++", "++", node.operator.location),
|
12556
|
+
node.operand.accept(self))
|
12557
|
+
end
|
12558
|
+
|
12559
|
+
def visit_compound_literal_expression(node)
|
12560
|
+
CompoundLiteralExpression.new(
|
12561
|
+
node.type_name, node.initializers.map { |ini| ini.accept(self) },
|
12562
|
+
node.operator)
|
12563
|
+
end
|
12564
|
+
|
12565
|
+
def visit_prefix_increment_expression(node)
|
12566
|
+
# NOTE: The prefix-increment-expression is already evaluated with
|
12567
|
+
# side-effect.
|
12568
|
+
# To rollback the side-effect, create an inverted expression.
|
12569
|
+
PostfixDecrementExpression.new(
|
12570
|
+
Token.new("--", "--", node.operator.location),
|
12571
|
+
node.operand.accept(self))
|
12572
|
+
end
|
12573
|
+
|
12574
|
+
def visit_prefix_decrement_expression(node)
|
12575
|
+
# NOTE: The prefix-decrement-expression is already evaluated with
|
12576
|
+
# side-effect.
|
12577
|
+
# To rollback the side-effect, create an inverted expression.
|
12578
|
+
PostfixIncrementExpression.new(
|
12579
|
+
Token.new("++", "++", node.operator.location),
|
12580
|
+
node.operand.accept(self))
|
12581
|
+
end
|
12582
|
+
|
12583
|
+
def visit_address_expression(node)
|
12584
|
+
AddressExpression.new(node.operator, node.operand.accept(self))
|
12585
|
+
end
|
12586
|
+
|
12587
|
+
def visit_indirection_expression(node)
|
12588
|
+
IndirectionExpression.new(node.operator, node.operand.accept(self))
|
12589
|
+
end
|
12590
|
+
|
12591
|
+
def visit_unary_arithmetic_expression(node)
|
12592
|
+
UnaryArithmeticExpression.new(node.operator, node.operand.accept(self))
|
12593
|
+
end
|
12594
|
+
|
12595
|
+
def visit_sizeof_expression(node)
|
12596
|
+
SizeofExpression.new(node.operator, node.operand.accept(self))
|
12597
|
+
end
|
12598
|
+
|
12599
|
+
def visit_sizeof_type_expression(node)
|
12600
|
+
node
|
12601
|
+
end
|
12602
|
+
|
12603
|
+
def visit_alignof_expression(node)
|
12604
|
+
AlignofExpression.new(node.operator, node.operand.accept(self))
|
12605
|
+
end
|
12606
|
+
|
12607
|
+
def visit_alignof_type_expression(node)
|
12608
|
+
node
|
12609
|
+
end
|
12610
|
+
|
12611
|
+
def visit_cast_expression(node)
|
12612
|
+
CastExpression.new(node.type_name, node.operand.accept(self))
|
12613
|
+
end
|
12614
|
+
|
12615
|
+
def visit_multiplicative_expression(node)
|
12616
|
+
MultiplicativeExpression.new(node.operator,
|
12617
|
+
node.lhs_operand.accept(self),
|
12618
|
+
node.rhs_operand.accept(self))
|
12619
|
+
end
|
12620
|
+
|
12621
|
+
def visit_additive_expression(node)
|
12622
|
+
AdditiveExpression.new(node.operator,
|
12623
|
+
node.lhs_operand.accept(self),
|
12624
|
+
node.rhs_operand.accept(self))
|
12625
|
+
end
|
12626
|
+
|
12627
|
+
def visit_shift_expression(node)
|
12628
|
+
ShiftExpression.new(node.operator,
|
12629
|
+
node.lhs_operand.accept(self),
|
12630
|
+
node.rhs_operand.accept(self))
|
12631
|
+
end
|
12632
|
+
|
12633
|
+
def visit_relational_expression(node)
|
12634
|
+
RelationalExpression.new(node.operator,
|
12635
|
+
node.lhs_operand.accept(self),
|
12636
|
+
node.rhs_operand.accept(self))
|
12637
|
+
end
|
12638
|
+
|
12639
|
+
def visit_equality_expression(node)
|
12640
|
+
EqualityExpression.new(node.operator,
|
12641
|
+
node.lhs_operand.accept(self),
|
12642
|
+
node.rhs_operand.accept(self))
|
12643
|
+
end
|
12644
|
+
|
12645
|
+
def visit_and_expression(node)
|
12646
|
+
AndExpression.new(node.operator,
|
12647
|
+
node.lhs_operand.accept(self),
|
12648
|
+
node.rhs_operand.accept(self))
|
12649
|
+
end
|
12650
|
+
|
12651
|
+
def visit_exclusive_or_expression(node)
|
12652
|
+
ExclusiveOrExpression.new(node.operator,
|
12653
|
+
node.lhs_operand.accept(self),
|
12654
|
+
node.rhs_operand.accept(self))
|
12655
|
+
end
|
12656
|
+
|
12657
|
+
def visit_inclusive_or_expression(node)
|
12658
|
+
InclusiveOrExpression.new(node.operator,
|
12659
|
+
node.lhs_operand.accept(self),
|
12660
|
+
node.rhs_operand.accept(self))
|
12661
|
+
end
|
12662
|
+
|
12663
|
+
def visit_logical_and_expression(node)
|
12664
|
+
LogicalAndExpression.new(node.operator,
|
12665
|
+
node.lhs_operand.accept(self),
|
12666
|
+
node.rhs_operand.accept(self))
|
12667
|
+
end
|
12668
|
+
|
12669
|
+
def visit_logical_or_expression(node)
|
12670
|
+
LogicalOrExpression.new(node.operator,
|
12671
|
+
node.lhs_operand.accept(self),
|
12672
|
+
node.rhs_operand.accept(self))
|
12673
|
+
end
|
12674
|
+
|
12675
|
+
def visit_conditional_expression(node)
|
12676
|
+
ConditionalExpression.new(node.condition.accept(self),
|
12677
|
+
node.then_expression.accept(self),
|
12678
|
+
node.else_expression.accept(self),
|
12679
|
+
Token.new("?", "?", node.location))
|
12680
|
+
end
|
12681
|
+
|
12682
|
+
def visit_simple_assignment_expression(node)
|
12683
|
+
SimpleAssignmentExpression.new(node.operator,
|
12684
|
+
node.lhs_operand.accept(self),
|
12685
|
+
node.rhs_operand.accept(self))
|
12686
|
+
end
|
12687
|
+
|
12688
|
+
def visit_compound_assignment_expression(node)
|
12689
|
+
CompoundAssignmentExpression.new(node.operator,
|
12690
|
+
node.lhs_operand.accept(self),
|
12691
|
+
node.rhs_operand.accept(self))
|
12692
|
+
end
|
12693
|
+
|
12694
|
+
def visit_comma_separated_expression(node)
|
12695
|
+
expressions = node.expressions.map { |expr| expr.accept(self) }
|
12696
|
+
result = CommaSeparatedExpression.new(expressions.shift)
|
12697
|
+
expressions.each { |expr| result.expressions.push(expr) }
|
12698
|
+
result
|
12699
|
+
end
|
12700
|
+
|
12701
|
+
def visit_initializer(node)
|
12702
|
+
case
|
12703
|
+
when node.expression
|
12704
|
+
Initializer.new(node.expression.accept(self), nil)
|
12705
|
+
when node.initializers
|
12706
|
+
Initializer.new(nil, node.initializers.map { |i| i.accept(self) })
|
12707
|
+
end
|
12339
12708
|
end
|
12340
12709
|
end
|
12710
|
+
private_constant :ExpressionTransformer
|
12711
|
+
end
|
12712
|
+
|
12713
|
+
class W0707 < PassiveMessageDetection
|
12714
|
+
include SyntaxNodeCollector
|
12715
|
+
include InterpreterOptions
|
12716
|
+
|
12717
|
+
def initialize(context)
|
12718
|
+
super
|
12719
|
+
@interp = context[:c_interpreter]
|
12720
|
+
@interp.on_array_subscript_expr_evaled += method(:check_array_subscript)
|
12721
|
+
@interp.on_indirection_expr_evaled += method(:check_indirection)
|
12722
|
+
@enum_tbl = @interp.environment.enumerator_table
|
12723
|
+
end
|
12724
|
+
|
12725
|
+
private
|
12726
|
+
def check_array_subscript(expression, *, subscript, array, result)
|
12727
|
+
return unless array
|
12728
|
+
|
12729
|
+
if expression.array_subscript.constant?(@enum_tbl)
|
12730
|
+
warn_array_oob_access(expression.array_subscript, array, subscript)
|
12731
|
+
end
|
12732
|
+
end
|
12733
|
+
|
12734
|
+
def check_indirection(expression, *)
|
12735
|
+
array, subscript_expr = extract_array_and_subscript(expression.operand)
|
12736
|
+
return unless array
|
12737
|
+
|
12738
|
+
if subscript_expr.constant?(@enum_tbl)
|
12739
|
+
# NOTE: A constant-expression has no side-effects.
|
12740
|
+
subscript = @interp.interpret(subscript_expr, QUIET)
|
12741
|
+
warn_array_oob_access(expression.operand, array, subscript)
|
12742
|
+
end
|
12743
|
+
end
|
12744
|
+
|
12745
|
+
def warn_array_oob_access(expression, array, subscript)
|
12746
|
+
if array_length = array.type.length
|
12747
|
+
lower_bound = ScalarValue.of(0)
|
12748
|
+
upper_bound = ScalarValue.of(array_length - 1)
|
12749
|
+
|
12750
|
+
lower_test = subscript.value < lower_bound
|
12751
|
+
upper_test = subscript.value > upper_bound
|
12752
|
+
|
12753
|
+
if lower_test.must_be_true? || upper_test.must_be_true?
|
12754
|
+
W(:W0707, expression.location)
|
12755
|
+
end
|
12756
|
+
end
|
12757
|
+
end
|
12758
|
+
|
12759
|
+
def extract_array_and_subscript(expression)
|
12760
|
+
array, array_name = extract_array(expression)
|
12761
|
+
subscript_expr = create_subscript_expr(expression, array_name)
|
12762
|
+
return array, subscript_expr
|
12763
|
+
end
|
12764
|
+
|
12765
|
+
def extract_array(expression)
|
12766
|
+
collect_object_specifiers(expression).each do |os|
|
12767
|
+
if object = @interp.variable_named(os.identifier.value)
|
12768
|
+
case
|
12769
|
+
when object.type.array?
|
12770
|
+
return object, os.identifier.value
|
12771
|
+
when object.type.pointer?
|
12772
|
+
if object = @interp.pointee_of(object) and object.type.array?
|
12773
|
+
return object, os.identifier.value
|
12774
|
+
end
|
12775
|
+
end
|
12776
|
+
end
|
12777
|
+
end
|
12778
|
+
nil
|
12779
|
+
end
|
12780
|
+
|
12781
|
+
def create_subscript_expr(expression, array_name)
|
12782
|
+
expression.accept(ExpressionTransformer.new(array_name))
|
12783
|
+
end
|
12784
|
+
|
12785
|
+
class ExpressionTransformer < SyntaxTreeVisitor
|
12786
|
+
def initialize(array_name)
|
12787
|
+
@array_name = array_name
|
12788
|
+
end
|
12789
|
+
|
12790
|
+
def visit_error_expression(node)
|
12791
|
+
node
|
12792
|
+
end
|
12793
|
+
|
12794
|
+
def visit_object_specifier(node)
|
12795
|
+
if node.identifier.value == @array_name
|
12796
|
+
ConstantSpecifier.new(Token.new(:CONSTANT, "0", node.location))
|
12797
|
+
else
|
12798
|
+
node
|
12799
|
+
end
|
12800
|
+
end
|
12801
|
+
|
12802
|
+
def visit_constant_specifier(node)
|
12803
|
+
node
|
12804
|
+
end
|
12805
|
+
|
12806
|
+
def visit_string_literal_specifier(node)
|
12807
|
+
node
|
12808
|
+
end
|
12809
|
+
|
12810
|
+
def visit_null_constant_specifier(node)
|
12811
|
+
node
|
12812
|
+
end
|
12813
|
+
|
12814
|
+
def visit_grouped_expression(node)
|
12815
|
+
GroupedExpression.new(node.expression.accept(self))
|
12816
|
+
end
|
12817
|
+
|
12818
|
+
def visit_array_subscript_expression(node)
|
12819
|
+
ArraySubscriptExpression.new(node.expression.accept(self),
|
12820
|
+
node.array_subscript.accept(self),
|
12821
|
+
node.operator)
|
12822
|
+
end
|
12823
|
+
|
12824
|
+
def visit_function_call_expression(node)
|
12825
|
+
FunctionCallExpression.new(
|
12826
|
+
node.expression.accept(self),
|
12827
|
+
node.argument_expressions.map { |expr| expr.accept(self) },
|
12828
|
+
node.operator)
|
12829
|
+
end
|
12830
|
+
|
12831
|
+
def visit_member_access_by_value_expression(node)
|
12832
|
+
MemberAccessByValueExpression.new(node.expression.accept(self),
|
12833
|
+
node.identifier, node.operator)
|
12834
|
+
end
|
12835
|
+
|
12836
|
+
def visit_member_access_by_pointer_expression(node)
|
12837
|
+
MemberAccessByPointerExpression.new(node.expression.accept(self),
|
12838
|
+
node.identifier, node.operator)
|
12839
|
+
end
|
12840
|
+
|
12841
|
+
def visit_bit_access_by_value_expression(node)
|
12842
|
+
BitAccessByValueExpression.new(node.expression.accept(self),
|
12843
|
+
node.constant, node.operator)
|
12844
|
+
end
|
12845
|
+
|
12846
|
+
def visit_bit_access_by_pointer_expression(node)
|
12847
|
+
BitAccessByPointerExpression.new(node.expression.accept(self),
|
12848
|
+
node.constant, node.operator)
|
12849
|
+
end
|
12850
|
+
|
12851
|
+
def visit_postfix_increment_expression(node)
|
12852
|
+
# NOTE: The postfix-increment-expression is already evaluated with
|
12853
|
+
# side-effect.
|
12854
|
+
# To rollback the side-effect, create an inverted expression.
|
12855
|
+
PrefixDecrementExpression.new(
|
12856
|
+
Token.new("--", "--", node.operator.location),
|
12857
|
+
node.operand.accept(self))
|
12858
|
+
end
|
12859
|
+
|
12860
|
+
def visit_postfix_decrement_expression(node)
|
12861
|
+
# NOTE: The postfix-decrement-expression is already evaluated with
|
12862
|
+
# side-effect.
|
12863
|
+
# To rollback the side-effect, create an inverted expression.
|
12864
|
+
PrefixIncrementExpression.new(
|
12865
|
+
Token.new("++", "++", node.operator.location),
|
12866
|
+
node.operand.accept(self))
|
12867
|
+
end
|
12868
|
+
|
12869
|
+
def visit_compound_literal_expression(node)
|
12870
|
+
CompoundLiteralExpression.new(
|
12871
|
+
node.type_name, node.initializers.map { |ini| ini.accept(self) },
|
12872
|
+
node.operator)
|
12873
|
+
end
|
12874
|
+
|
12875
|
+
def visit_prefix_increment_expression(node)
|
12876
|
+
# NOTE: The prefix-increment-expression is already evaluated with
|
12877
|
+
# side-effect.
|
12878
|
+
# To rollback the side-effect, create an inverted expression.
|
12879
|
+
PostfixDecrementExpression.new(
|
12880
|
+
Token.new("--", "--", node.operator.location),
|
12881
|
+
node.operand.accept(self))
|
12882
|
+
end
|
12883
|
+
|
12884
|
+
def visit_prefix_decrement_expression(node)
|
12885
|
+
# NOTE: The prefix-decrement-expression is already evaluated with
|
12886
|
+
# side-effect.
|
12887
|
+
# To rollback the side-effect, create an inverted expression.
|
12888
|
+
PostfixIncrementExpression.new(
|
12889
|
+
Token.new("++", "++", node.operator.location),
|
12890
|
+
node.operand.accept(self))
|
12891
|
+
end
|
12892
|
+
|
12893
|
+
def visit_address_expression(node)
|
12894
|
+
AddressExpression.new(node.operator, node.operand.accept(self))
|
12895
|
+
end
|
12896
|
+
|
12897
|
+
def visit_indirection_expression(node)
|
12898
|
+
IndirectionExpression.new(node.operator, node.operand.accept(self))
|
12899
|
+
end
|
12900
|
+
|
12901
|
+
def visit_unary_arithmetic_expression(node)
|
12902
|
+
UnaryArithmeticExpression.new(node.operator, node.operand.accept(self))
|
12903
|
+
end
|
12904
|
+
|
12905
|
+
def visit_sizeof_expression(node)
|
12906
|
+
SizeofExpression.new(node.operator, node.operand.accept(self))
|
12907
|
+
end
|
12908
|
+
|
12909
|
+
def visit_sizeof_type_expression(node)
|
12910
|
+
node
|
12911
|
+
end
|
12912
|
+
|
12913
|
+
def visit_alignof_expression(node)
|
12914
|
+
AlignofExpression.new(node.operator, node.operand.accept(self))
|
12915
|
+
end
|
12916
|
+
|
12917
|
+
def visit_alignof_type_expression(node)
|
12918
|
+
node
|
12919
|
+
end
|
12920
|
+
|
12921
|
+
def visit_cast_expression(node)
|
12922
|
+
CastExpression.new(node.type_name, node.operand.accept(self))
|
12923
|
+
end
|
12924
|
+
|
12925
|
+
def visit_multiplicative_expression(node)
|
12926
|
+
MultiplicativeExpression.new(node.operator,
|
12927
|
+
node.lhs_operand.accept(self),
|
12928
|
+
node.rhs_operand.accept(self))
|
12929
|
+
end
|
12930
|
+
|
12931
|
+
def visit_additive_expression(node)
|
12932
|
+
AdditiveExpression.new(node.operator,
|
12933
|
+
node.lhs_operand.accept(self),
|
12934
|
+
node.rhs_operand.accept(self))
|
12935
|
+
end
|
12936
|
+
|
12937
|
+
def visit_shift_expression(node)
|
12938
|
+
ShiftExpression.new(node.operator,
|
12939
|
+
node.lhs_operand.accept(self),
|
12940
|
+
node.rhs_operand.accept(self))
|
12941
|
+
end
|
12942
|
+
|
12943
|
+
def visit_relational_expression(node)
|
12944
|
+
RelationalExpression.new(node.operator,
|
12945
|
+
node.lhs_operand.accept(self),
|
12946
|
+
node.rhs_operand.accept(self))
|
12947
|
+
end
|
12948
|
+
|
12949
|
+
def visit_equality_expression(node)
|
12950
|
+
EqualityExpression.new(node.operator,
|
12951
|
+
node.lhs_operand.accept(self),
|
12952
|
+
node.rhs_operand.accept(self))
|
12953
|
+
end
|
12954
|
+
|
12955
|
+
def visit_and_expression(node)
|
12956
|
+
AndExpression.new(node.operator,
|
12957
|
+
node.lhs_operand.accept(self),
|
12958
|
+
node.rhs_operand.accept(self))
|
12959
|
+
end
|
12960
|
+
|
12961
|
+
def visit_exclusive_or_expression(node)
|
12962
|
+
ExclusiveOrExpression.new(node.operator,
|
12963
|
+
node.lhs_operand.accept(self),
|
12964
|
+
node.rhs_operand.accept(self))
|
12965
|
+
end
|
12966
|
+
|
12967
|
+
def visit_inclusive_or_expression(node)
|
12968
|
+
InclusiveOrExpression.new(node.operator,
|
12969
|
+
node.lhs_operand.accept(self),
|
12970
|
+
node.rhs_operand.accept(self))
|
12971
|
+
end
|
12972
|
+
|
12973
|
+
def visit_logical_and_expression(node)
|
12974
|
+
LogicalAndExpression.new(node.operator,
|
12975
|
+
node.lhs_operand.accept(self),
|
12976
|
+
node.rhs_operand.accept(self))
|
12977
|
+
end
|
12978
|
+
|
12979
|
+
def visit_logical_or_expression(node)
|
12980
|
+
LogicalOrExpression.new(node.operator,
|
12981
|
+
node.lhs_operand.accept(self),
|
12982
|
+
node.rhs_operand.accept(self))
|
12983
|
+
end
|
12984
|
+
|
12985
|
+
def visit_conditional_expression(node)
|
12986
|
+
ConditionalExpression.new(node.condition.accept(self),
|
12987
|
+
node.then_expression.accept(self),
|
12988
|
+
node.else_expression.accept(self),
|
12989
|
+
Token.new("?", "?", node.location))
|
12990
|
+
end
|
12991
|
+
|
12992
|
+
def visit_simple_assignment_expression(node)
|
12993
|
+
SimpleAssignmentExpression.new(node.operator,
|
12994
|
+
node.lhs_operand.accept(self),
|
12995
|
+
node.rhs_operand.accept(self))
|
12996
|
+
end
|
12997
|
+
|
12998
|
+
def visit_compound_assignment_expression(node)
|
12999
|
+
CompoundAssignmentExpression.new(node.operator,
|
13000
|
+
node.lhs_operand.accept(self),
|
13001
|
+
node.rhs_operand.accept(self))
|
13002
|
+
end
|
13003
|
+
|
13004
|
+
def visit_comma_separated_expression(node)
|
13005
|
+
expressions = node.expressions.map { |expr| expr.accept(self) }
|
13006
|
+
result = CommaSeparatedExpression.new(expressions.shift)
|
13007
|
+
expressions.each { |expr| result.expressions.push(expr) }
|
13008
|
+
result
|
13009
|
+
end
|
13010
|
+
|
13011
|
+
def visit_initializer(node)
|
13012
|
+
case
|
13013
|
+
when node.expression
|
13014
|
+
Initializer.new(node.expression.accept(self), nil)
|
13015
|
+
when node.initializers
|
13016
|
+
Initializer.new(nil, node.initializers.map { |i| i.accept(self) })
|
13017
|
+
end
|
13018
|
+
end
|
13019
|
+
end
|
13020
|
+
private_constant :ExpressionTransformer
|
12341
13021
|
end
|
12342
13022
|
|
12343
13023
|
class W0708 < PassiveMessageDetection
|
@@ -12469,6 +13149,31 @@ module C #:nodoc:
|
|
12469
13149
|
private_constant :Visitor
|
12470
13150
|
end
|
12471
13151
|
|
13152
|
+
class W0719 < PassiveMessageDetection
|
13153
|
+
def initialize(context)
|
13154
|
+
super
|
13155
|
+
interp = context[:c_interpreter]
|
13156
|
+
interp.on_shift_expr_evaled += method(:check)
|
13157
|
+
@enum_tbl = interp.environment.enumerator_table
|
13158
|
+
end
|
13159
|
+
|
13160
|
+
private
|
13161
|
+
def check(expr, lhs_variable, rhs_variable, result_variable)
|
13162
|
+
if expr.rhs_operand.constant?(@enum_tbl)
|
13163
|
+
underlying_type = lhs_variable.type
|
13164
|
+
underlying_bit_size = ScalarValue.of(underlying_type.bit_size)
|
13165
|
+
promoted_type = lhs_variable.type.integer_promoted_type
|
13166
|
+
promoted_bit_size = ScalarValue.of(promoted_type.bit_size)
|
13167
|
+
|
13168
|
+
if rhs_variable.value.must_be_equal_to?(underlying_bit_size) ||
|
13169
|
+
rhs_variable.value.must_be_greater_than?(underlying_bit_size) and
|
13170
|
+
rhs_variable.value.must_be_less_than?(promoted_bit_size)
|
13171
|
+
W(:W0719, expr.location)
|
13172
|
+
end
|
13173
|
+
end
|
13174
|
+
end
|
13175
|
+
end
|
13176
|
+
|
12472
13177
|
class W0720 < PassiveMessageDetection
|
12473
13178
|
def initialize(context)
|
12474
13179
|
super
|
@@ -13042,29 +13747,314 @@ module C #:nodoc:
|
|
13042
13747
|
end
|
13043
13748
|
|
13044
13749
|
class W0745 < PassiveMessageDetection
|
13750
|
+
include SyntaxNodeCollector
|
13751
|
+
include InterpreterOptions
|
13752
|
+
|
13045
13753
|
def initialize(context)
|
13046
13754
|
super
|
13047
|
-
interp = context[:c_interpreter]
|
13048
|
-
interp.on_array_subscript_expr_evaled += method(:
|
13755
|
+
@interp = context[:c_interpreter]
|
13756
|
+
@interp.on_array_subscript_expr_evaled += method(:check_array_subscript)
|
13757
|
+
@interp.on_indirection_expr_evaled += method(:check_indirection)
|
13758
|
+
@enum_tbl = @interp.environment.enumerator_table
|
13049
13759
|
end
|
13050
13760
|
|
13051
|
-
private
|
13052
|
-
def
|
13053
|
-
|
13054
|
-
|
13055
|
-
|
13056
|
-
|
13761
|
+
private
|
13762
|
+
def check_array_subscript(expression, *, subscript, array, result)
|
13763
|
+
return unless array
|
13764
|
+
|
13765
|
+
unless expression.array_subscript.constant?(@enum_tbl)
|
13766
|
+
warn_array_oob_access(expression.array_subscript, array, subscript)
|
13767
|
+
end
|
13768
|
+
end
|
13769
|
+
|
13770
|
+
def check_indirection(expression, *)
|
13771
|
+
array, subscript_expr = extract_array_and_subscript(expression.operand)
|
13772
|
+
return unless array
|
13773
|
+
|
13774
|
+
unless subscript_expr.constant?(@enum_tbl)
|
13775
|
+
subscript = @interp.interpret(subscript_expr,
|
13776
|
+
QUIET_WITHOUT_SIDE_EFFECT)
|
13777
|
+
warn_array_oob_access(expression.operand, array, subscript)
|
13778
|
+
end
|
13779
|
+
end
|
13780
|
+
|
13781
|
+
def warn_array_oob_access(expression, array, subscript)
|
13782
|
+
if array_length = array.type.length
|
13783
|
+
lower_bound = ScalarValue.of(0)
|
13784
|
+
upper_bound = ScalarValue.of(array_length - 1)
|
13785
|
+
|
13786
|
+
lower_test = subscript.value < lower_bound
|
13787
|
+
upper_test = subscript.value > upper_bound
|
13788
|
+
|
13789
|
+
if lower_test.must_be_true? || upper_test.must_be_true?
|
13790
|
+
W(:W0745, expression.location)
|
13791
|
+
end
|
13792
|
+
end
|
13793
|
+
end
|
13794
|
+
|
13795
|
+
def extract_array_and_subscript(expression)
|
13796
|
+
array, array_name = extract_array(expression)
|
13797
|
+
subscript_expr = create_subscript_expr(expression, array_name)
|
13798
|
+
return array, subscript_expr
|
13799
|
+
end
|
13800
|
+
|
13801
|
+
def extract_array(expression)
|
13802
|
+
collect_object_specifiers(expression).each do |os|
|
13803
|
+
if object = @interp.variable_named(os.identifier.value)
|
13804
|
+
case
|
13805
|
+
when object.type.array?
|
13806
|
+
return object, os.identifier.value
|
13807
|
+
when object.type.pointer?
|
13808
|
+
if object = @interp.pointee_of(object) and object.type.array?
|
13809
|
+
return object, os.identifier.value
|
13810
|
+
end
|
13811
|
+
end
|
13812
|
+
end
|
13813
|
+
end
|
13814
|
+
nil
|
13815
|
+
end
|
13816
|
+
|
13817
|
+
def create_subscript_expr(expression, array_name)
|
13818
|
+
expression.accept(ExpressionTransformer.new(array_name))
|
13819
|
+
end
|
13820
|
+
|
13821
|
+
class ExpressionTransformer < SyntaxTreeVisitor
|
13822
|
+
def initialize(array_name)
|
13823
|
+
@array_name = array_name
|
13824
|
+
end
|
13825
|
+
|
13826
|
+
def visit_error_expression(node)
|
13827
|
+
node
|
13828
|
+
end
|
13829
|
+
|
13830
|
+
def visit_object_specifier(node)
|
13831
|
+
if node.identifier.value == @array_name
|
13832
|
+
ConstantSpecifier.new(Token.new(:CONSTANT, "0", node.location))
|
13833
|
+
else
|
13834
|
+
node
|
13835
|
+
end
|
13836
|
+
end
|
13837
|
+
|
13838
|
+
def visit_constant_specifier(node)
|
13839
|
+
node
|
13840
|
+
end
|
13841
|
+
|
13842
|
+
def visit_string_literal_specifier(node)
|
13843
|
+
node
|
13844
|
+
end
|
13845
|
+
|
13846
|
+
def visit_null_constant_specifier(node)
|
13847
|
+
node
|
13848
|
+
end
|
13849
|
+
|
13850
|
+
def visit_grouped_expression(node)
|
13851
|
+
GroupedExpression.new(node.expression.accept(self))
|
13852
|
+
end
|
13853
|
+
|
13854
|
+
def visit_array_subscript_expression(node)
|
13855
|
+
ArraySubscriptExpression.new(node.expression.accept(self),
|
13856
|
+
node.array_subscript.accept(self),
|
13857
|
+
node.operator)
|
13858
|
+
end
|
13859
|
+
|
13860
|
+
def visit_function_call_expression(node)
|
13861
|
+
FunctionCallExpression.new(
|
13862
|
+
node.expression.accept(self),
|
13863
|
+
node.argument_expressions.map { |expr| expr.accept(self) },
|
13864
|
+
node.operator)
|
13865
|
+
end
|
13866
|
+
|
13867
|
+
def visit_member_access_by_value_expression(node)
|
13868
|
+
MemberAccessByValueExpression.new(node.expression.accept(self),
|
13869
|
+
node.identifier, node.operator)
|
13870
|
+
end
|
13871
|
+
|
13872
|
+
def visit_member_access_by_pointer_expression(node)
|
13873
|
+
MemberAccessByPointerExpression.new(node.expression.accept(self),
|
13874
|
+
node.identifier, node.operator)
|
13875
|
+
end
|
13876
|
+
|
13877
|
+
def visit_bit_access_by_value_expression(node)
|
13878
|
+
BitAccessByValueExpression.new(node.expression.accept(self),
|
13879
|
+
node.constant, node.operator)
|
13880
|
+
end
|
13881
|
+
|
13882
|
+
def visit_bit_access_by_pointer_expression(node)
|
13883
|
+
BitAccessByPointerExpression.new(node.expression.accept(self),
|
13884
|
+
node.constant, node.operator)
|
13885
|
+
end
|
13886
|
+
|
13887
|
+
def visit_postfix_increment_expression(node)
|
13888
|
+
# NOTE: The postfix-increment-expression is already evaluated with
|
13889
|
+
# side-effect.
|
13890
|
+
# To rollback the side-effect, create an inverted expression.
|
13891
|
+
PrefixDecrementExpression.new(
|
13892
|
+
Token.new("--", "--", node.operator.location),
|
13893
|
+
node.operand.accept(self))
|
13894
|
+
end
|
13895
|
+
|
13896
|
+
def visit_postfix_decrement_expression(node)
|
13897
|
+
# NOTE: The postfix-decrement-expression is already evaluated with
|
13898
|
+
# side-effect.
|
13899
|
+
# To rollback the side-effect, create an inverted expression.
|
13900
|
+
PrefixIncrementExpression.new(
|
13901
|
+
Token.new("++", "++", node.operator.location),
|
13902
|
+
node.operand.accept(self))
|
13903
|
+
end
|
13904
|
+
|
13905
|
+
def visit_compound_literal_expression(node)
|
13906
|
+
CompoundLiteralExpression.new(
|
13907
|
+
node.type_name, node.initializers.map { |ini| ini.accept(self) },
|
13908
|
+
node.operator)
|
13909
|
+
end
|
13910
|
+
|
13911
|
+
def visit_prefix_increment_expression(node)
|
13912
|
+
# NOTE: The prefix-increment-expression is already evaluated with
|
13913
|
+
# side-effect.
|
13914
|
+
# To rollback the side-effect, create an inverted expression.
|
13915
|
+
PostfixDecrementExpression.new(
|
13916
|
+
Token.new("--", "--", node.operator.location),
|
13917
|
+
node.operand.accept(self))
|
13918
|
+
end
|
13919
|
+
|
13920
|
+
def visit_prefix_decrement_expression(node)
|
13921
|
+
# NOTE: The prefix-decrement-expression is already evaluated with
|
13922
|
+
# side-effect.
|
13923
|
+
# To rollback the side-effect, create an inverted expression.
|
13924
|
+
PostfixIncrementExpression.new(
|
13925
|
+
Token.new("++", "++", node.operator.location),
|
13926
|
+
node.operand.accept(self))
|
13927
|
+
end
|
13928
|
+
|
13929
|
+
def visit_address_expression(node)
|
13930
|
+
AddressExpression.new(node.operator, node.operand.accept(self))
|
13931
|
+
end
|
13932
|
+
|
13933
|
+
def visit_indirection_expression(node)
|
13934
|
+
IndirectionExpression.new(node.operator, node.operand.accept(self))
|
13935
|
+
end
|
13936
|
+
|
13937
|
+
def visit_unary_arithmetic_expression(node)
|
13938
|
+
UnaryArithmeticExpression.new(node.operator, node.operand.accept(self))
|
13939
|
+
end
|
13940
|
+
|
13941
|
+
def visit_sizeof_expression(node)
|
13942
|
+
SizeofExpression.new(node.operator, node.operand.accept(self))
|
13943
|
+
end
|
13944
|
+
|
13945
|
+
def visit_sizeof_type_expression(node)
|
13946
|
+
node
|
13947
|
+
end
|
13948
|
+
|
13949
|
+
def visit_alignof_expression(node)
|
13950
|
+
AlignofExpression.new(node.operator, node.operand.accept(self))
|
13951
|
+
end
|
13952
|
+
|
13953
|
+
def visit_alignof_type_expression(node)
|
13954
|
+
node
|
13955
|
+
end
|
13956
|
+
|
13957
|
+
def visit_cast_expression(node)
|
13958
|
+
CastExpression.new(node.type_name, node.operand.accept(self))
|
13959
|
+
end
|
13960
|
+
|
13961
|
+
def visit_multiplicative_expression(node)
|
13962
|
+
MultiplicativeExpression.new(node.operator,
|
13963
|
+
node.lhs_operand.accept(self),
|
13964
|
+
node.rhs_operand.accept(self))
|
13965
|
+
end
|
13966
|
+
|
13967
|
+
def visit_additive_expression(node)
|
13968
|
+
AdditiveExpression.new(node.operator,
|
13969
|
+
node.lhs_operand.accept(self),
|
13970
|
+
node.rhs_operand.accept(self))
|
13971
|
+
end
|
13972
|
+
|
13973
|
+
def visit_shift_expression(node)
|
13974
|
+
ShiftExpression.new(node.operator,
|
13975
|
+
node.lhs_operand.accept(self),
|
13976
|
+
node.rhs_operand.accept(self))
|
13977
|
+
end
|
13978
|
+
|
13979
|
+
def visit_relational_expression(node)
|
13980
|
+
RelationalExpression.new(node.operator,
|
13981
|
+
node.lhs_operand.accept(self),
|
13982
|
+
node.rhs_operand.accept(self))
|
13983
|
+
end
|
13984
|
+
|
13985
|
+
def visit_equality_expression(node)
|
13986
|
+
EqualityExpression.new(node.operator,
|
13987
|
+
node.lhs_operand.accept(self),
|
13988
|
+
node.rhs_operand.accept(self))
|
13989
|
+
end
|
13990
|
+
|
13991
|
+
def visit_and_expression(node)
|
13992
|
+
AndExpression.new(node.operator,
|
13993
|
+
node.lhs_operand.accept(self),
|
13994
|
+
node.rhs_operand.accept(self))
|
13995
|
+
end
|
13996
|
+
|
13997
|
+
def visit_exclusive_or_expression(node)
|
13998
|
+
ExclusiveOrExpression.new(node.operator,
|
13999
|
+
node.lhs_operand.accept(self),
|
14000
|
+
node.rhs_operand.accept(self))
|
14001
|
+
end
|
14002
|
+
|
14003
|
+
def visit_inclusive_or_expression(node)
|
14004
|
+
InclusiveOrExpression.new(node.operator,
|
14005
|
+
node.lhs_operand.accept(self),
|
14006
|
+
node.rhs_operand.accept(self))
|
14007
|
+
end
|
14008
|
+
|
14009
|
+
def visit_logical_and_expression(node)
|
14010
|
+
LogicalAndExpression.new(node.operator,
|
14011
|
+
node.lhs_operand.accept(self),
|
14012
|
+
node.rhs_operand.accept(self))
|
14013
|
+
end
|
14014
|
+
|
14015
|
+
def visit_logical_or_expression(node)
|
14016
|
+
LogicalOrExpression.new(node.operator,
|
14017
|
+
node.lhs_operand.accept(self),
|
14018
|
+
node.rhs_operand.accept(self))
|
14019
|
+
end
|
14020
|
+
|
14021
|
+
def visit_conditional_expression(node)
|
14022
|
+
ConditionalExpression.new(node.condition.accept(self),
|
14023
|
+
node.then_expression.accept(self),
|
14024
|
+
node.else_expression.accept(self),
|
14025
|
+
Token.new("?", "?", node.location))
|
14026
|
+
|
14027
|
+
end
|
14028
|
+
|
14029
|
+
def visit_simple_assignment_expression(node)
|
14030
|
+
SimpleAssignmentExpression.new(node.operator,
|
14031
|
+
node.lhs_operand.accept(self),
|
14032
|
+
node.rhs_operand.accept(self))
|
14033
|
+
end
|
13057
14034
|
|
13058
|
-
|
13059
|
-
|
14035
|
+
def visit_compound_assignment_expression(node)
|
14036
|
+
CompoundAssignmentExpression.new(node.operator,
|
14037
|
+
node.lhs_operand.accept(self),
|
14038
|
+
node.rhs_operand.accept(self))
|
14039
|
+
end
|
13060
14040
|
|
13061
|
-
|
13062
|
-
|
14041
|
+
def visit_comma_separated_expression(node)
|
14042
|
+
expressions = node.expressions.map { |expr| expr.accept(self) }
|
14043
|
+
result = CommaSeparatedExpression.new(expressions.shift)
|
14044
|
+
expressions.each { |expr| result.expressions.push(expr) }
|
14045
|
+
result
|
14046
|
+
end
|
13063
14047
|
|
13064
|
-
|
13065
|
-
|
14048
|
+
def visit_initializer(node)
|
14049
|
+
case
|
14050
|
+
when node.expression
|
14051
|
+
Initializer.new(node.expression.accept(self), nil)
|
14052
|
+
when node.initializers
|
14053
|
+
Initializer.new(nil, node.initializers.map { |i| i.accept(self) })
|
14054
|
+
end
|
13066
14055
|
end
|
13067
14056
|
end
|
14057
|
+
private_constant :ExpressionTransformer
|
13068
14058
|
end
|
13069
14059
|
|
13070
14060
|
class W0747 < W0119
|
@@ -13481,6 +14471,54 @@ module C #:nodoc:
|
|
13481
14471
|
end
|
13482
14472
|
end
|
13483
14473
|
|
14474
|
+
class W0780 < PassiveMessageDetection
|
14475
|
+
def initialize(context)
|
14476
|
+
super
|
14477
|
+
interp = context[:c_interpreter]
|
14478
|
+
interp.on_shift_expr_evaled += method(:check)
|
14479
|
+
@enum_tbl = interp.environment.enumerator_table
|
14480
|
+
end
|
14481
|
+
|
14482
|
+
private
|
14483
|
+
def check(expression, lhs_variable, rhs_variable, result_variable)
|
14484
|
+
operator = expression.operator.type
|
14485
|
+
return unless operator == "<<" || operator == "<<="
|
14486
|
+
|
14487
|
+
if lhs_variable.type.unsigned? && expression.constant?(@enum_tbl)
|
14488
|
+
if must_overflow?(lhs_variable, rhs_variable)
|
14489
|
+
W(:W0780, expression.location)
|
14490
|
+
end
|
14491
|
+
end
|
14492
|
+
end
|
14493
|
+
|
14494
|
+
def must_overflow?(lhs_variable, rhs_variable)
|
14495
|
+
result = lhs_variable.value << rhs_variable.value
|
14496
|
+
result.must_be_greater_than?(ScalarValue.of(lhs_variable.type.max_value))
|
14497
|
+
end
|
14498
|
+
end
|
14499
|
+
|
14500
|
+
class W0783 < PassiveMessageDetection
|
14501
|
+
def initialize(context)
|
14502
|
+
super
|
14503
|
+
interp = context[:c_interpreter]
|
14504
|
+
interp.on_explicit_conv_performed += method(:check)
|
14505
|
+
end
|
14506
|
+
|
14507
|
+
private
|
14508
|
+
def check(expression, original_variable, result_variable)
|
14509
|
+
from_type = original_variable.type.unqualify
|
14510
|
+
to_type = result_variable.type.unqualify
|
14511
|
+
|
14512
|
+
return unless from_type.pointer? && to_type.pointer?
|
14513
|
+
|
14514
|
+
unless from_type.base_type.void? || to_type.base_type.void?
|
14515
|
+
if from_type.base_type.incomplete? || to_type.base_type.incomplete?
|
14516
|
+
W(:W0783, expression.location)
|
14517
|
+
end
|
14518
|
+
end
|
14519
|
+
end
|
14520
|
+
end
|
14521
|
+
|
13484
14522
|
class W0785 < PassiveMessageDetection
|
13485
14523
|
def initialize(context)
|
13486
14524
|
super
|
@@ -14010,6 +15048,73 @@ module C #:nodoc:
|
|
14010
15048
|
end
|
14011
15049
|
end
|
14012
15050
|
|
15051
|
+
class W0792 < PassiveMessageDetection
|
15052
|
+
def initialize(context)
|
15053
|
+
super
|
15054
|
+
interp = context[:c_interpreter]
|
15055
|
+
interp.on_explicit_conv_performed += method(:check)
|
15056
|
+
end
|
15057
|
+
|
15058
|
+
private
|
15059
|
+
def check(expression, original_variable, result_variable)
|
15060
|
+
lhs_type = original_variable.type.unqualify
|
15061
|
+
rhs_type = result_variable.type.unqualify
|
15062
|
+
|
15063
|
+
case
|
15064
|
+
when lhs_type.floating? &&
|
15065
|
+
rhs_type.pointer? && rhs_type.base_type.function?
|
15066
|
+
W(:W0792, expression.location)
|
15067
|
+
when rhs_type.floating? &&
|
15068
|
+
lhs_type.pointer? && lhs_type.base_type.function?
|
15069
|
+
W(:W0792, expression.location)
|
15070
|
+
end
|
15071
|
+
end
|
15072
|
+
end
|
15073
|
+
|
15074
|
+
class W0793 < PassiveMessageDetection
|
15075
|
+
def initialize(context)
|
15076
|
+
super
|
15077
|
+
interp = context[:c_interpreter]
|
15078
|
+
interp.on_explicit_conv_performed += method(:check)
|
15079
|
+
end
|
15080
|
+
|
15081
|
+
private
|
15082
|
+
def check(expression, original_variable, result_variable)
|
15083
|
+
lhs_type = original_variable.type.unqualify
|
15084
|
+
rhs_type = result_variable.type.unqualify
|
15085
|
+
|
15086
|
+
if lhs_type.pointer? && rhs_type.pointer?
|
15087
|
+
case
|
15088
|
+
when lhs_type.base_type.void? || rhs_type.base_type.void?
|
15089
|
+
# NOTE: Nothing to be done with conversion between `void *' and any
|
15090
|
+
# pointer and between `void *' and `void *'.
|
15091
|
+
when lhs_type.base_type.function? && !rhs_type.base_type.function?,
|
15092
|
+
rhs_type.base_type.function? && !lhs_type.base_type.function?
|
15093
|
+
W(:W0793, expression.location)
|
15094
|
+
end
|
15095
|
+
end
|
15096
|
+
end
|
15097
|
+
end
|
15098
|
+
|
15099
|
+
class W0794 < PassiveMessageDetection
|
15100
|
+
def initialize(context)
|
15101
|
+
super
|
15102
|
+
interp = context[:c_interpreter]
|
15103
|
+
interp.on_shift_expr_evaled += method(:check)
|
15104
|
+
@enum_tbl = interp.environment.enumerator_table
|
15105
|
+
end
|
15106
|
+
|
15107
|
+
private
|
15108
|
+
def check(expression, lhs_variable, *)
|
15109
|
+
case expression.operator.type
|
15110
|
+
when "<<", "<<="
|
15111
|
+
unless expression.lhs_operand.constant?(@enum_tbl)
|
15112
|
+
W(:W0794, expression.location) if lhs_variable.type.signed?
|
15113
|
+
end
|
15114
|
+
end
|
15115
|
+
end
|
15116
|
+
end
|
15117
|
+
|
14013
15118
|
class W0795 < PassiveMessageDetection
|
14014
15119
|
def initialize(context)
|
14015
15120
|
super
|
@@ -14312,6 +15417,133 @@ module C #:nodoc:
|
|
14312
15417
|
end
|
14313
15418
|
end
|
14314
15419
|
|
15420
|
+
class W0830 < PassiveMessageDetection
|
15421
|
+
def initialize(context)
|
15422
|
+
super
|
15423
|
+
visitor = context[:c_visitor]
|
15424
|
+
visitor.enter_enum_specifier += method(:check)
|
15425
|
+
end
|
15426
|
+
|
15427
|
+
private
|
15428
|
+
def check(enum_specifier)
|
15429
|
+
if extra_comma = enum_specifier.trailing_comma
|
15430
|
+
W(:W0830, extra_comma.location)
|
15431
|
+
end
|
15432
|
+
end
|
15433
|
+
end
|
15434
|
+
|
15435
|
+
class W0833 < PassiveMessageDetection
|
15436
|
+
def initialize(context)
|
15437
|
+
super
|
15438
|
+
interp = context[:c_interpreter]
|
15439
|
+
interp.on_constant_referred += method(:check)
|
15440
|
+
end
|
15441
|
+
|
15442
|
+
private
|
15443
|
+
def check(constant_specifier, *)
|
15444
|
+
if constant_specifier.constant.value =~ /LL/i
|
15445
|
+
W(:W0833, constant_specifier.location)
|
15446
|
+
end
|
15447
|
+
end
|
15448
|
+
end
|
15449
|
+
|
15450
|
+
class W0834 < PassiveMessageDetection
|
15451
|
+
# NOTE: W0834 may be duplicative on a function-definition because
|
15452
|
+
# function-definition has both parameter-declarations and
|
15453
|
+
# parameter-definitions.
|
15454
|
+
ensure_uniqueness_of :W0834
|
15455
|
+
|
15456
|
+
def initialize(context)
|
15457
|
+
super
|
15458
|
+
visitor = context[:c_visitor]
|
15459
|
+
visitor.enter_member_declaration += method(:check_member_decl)
|
15460
|
+
visitor.enter_typedef_declaration += method(:check_declspec_holder)
|
15461
|
+
visitor.enter_function_declaration += method(:check_declspec_holder)
|
15462
|
+
visitor.enter_parameter_declaration += method(:check_declspec_holder)
|
15463
|
+
visitor.enter_variable_declaration += method(:check_declspec_holder)
|
15464
|
+
visitor.enter_variable_definition += method(:check_declspec_holder)
|
15465
|
+
visitor.enter_ansi_function_definition += method(:check_declspec_holder)
|
15466
|
+
visitor.enter_kandr_function_definition += method(:check_declspec_holder)
|
15467
|
+
visitor.enter_parameter_definition += method(:check_declspec_holder)
|
15468
|
+
visitor.enter_type_name += method(:check_type_name)
|
15469
|
+
end
|
15470
|
+
|
15471
|
+
private
|
15472
|
+
def check_member_decl(node)
|
15473
|
+
type_specifiers = node.specifier_qualifier_list.type_specifiers
|
15474
|
+
if first_ts = type_specifiers.first
|
15475
|
+
node.type.accept(Visitor.new(@context, first_ts.location))
|
15476
|
+
end
|
15477
|
+
end
|
15478
|
+
|
15479
|
+
def check_type_name(node)
|
15480
|
+
type_specifiers = node.specifier_qualifier_list.type_specifiers
|
15481
|
+
if first_ts = type_specifiers.first
|
15482
|
+
node.type.accept(Visitor.new(@context, first_ts.location))
|
15483
|
+
end
|
15484
|
+
end
|
15485
|
+
|
15486
|
+
def check_declspec_holder(declspec_holder)
|
15487
|
+
type_specifiers = declspec_holder.type_specifiers
|
15488
|
+
if first_ts = type_specifiers.first
|
15489
|
+
declspec_holder.type.accept(Visitor.new(@context, first_ts.location))
|
15490
|
+
end
|
15491
|
+
end
|
15492
|
+
|
15493
|
+
class Visitor < TypeVisitor
|
15494
|
+
include ReportUtil
|
15495
|
+
|
15496
|
+
def initialize(context, location)
|
15497
|
+
@context = context
|
15498
|
+
@location = location
|
15499
|
+
end
|
15500
|
+
|
15501
|
+
def visit_long_long_type(type)
|
15502
|
+
warn
|
15503
|
+
end
|
15504
|
+
|
15505
|
+
def visit_signed_long_long_type(type)
|
15506
|
+
warn
|
15507
|
+
end
|
15508
|
+
|
15509
|
+
def visit_unsigned_long_long_type(type)
|
15510
|
+
warn
|
15511
|
+
end
|
15512
|
+
|
15513
|
+
def visit_long_long_int_type(type)
|
15514
|
+
warn
|
15515
|
+
end
|
15516
|
+
|
15517
|
+
def visit_signed_long_long_int_type(type)
|
15518
|
+
warn
|
15519
|
+
end
|
15520
|
+
|
15521
|
+
def visit_unsigned_long_long_int_type(type)
|
15522
|
+
warn
|
15523
|
+
end
|
15524
|
+
|
15525
|
+
def visit_function_type(type)
|
15526
|
+
type.return_type.accept(self)
|
15527
|
+
end
|
15528
|
+
|
15529
|
+
def visit_struct_type(type)
|
15530
|
+
end
|
15531
|
+
|
15532
|
+
def visit_union_type(type)
|
15533
|
+
end
|
15534
|
+
|
15535
|
+
private
|
15536
|
+
def warn
|
15537
|
+
W(:W0834, @location)
|
15538
|
+
end
|
15539
|
+
|
15540
|
+
def report
|
15541
|
+
@context.report
|
15542
|
+
end
|
15543
|
+
end
|
15544
|
+
private_constant :Visitor
|
15545
|
+
end
|
15546
|
+
|
14315
15547
|
class W0947 < PassiveMessageDetection
|
14316
15548
|
def initialize(context)
|
14317
15549
|
super
|
@@ -14401,6 +15633,24 @@ module C #:nodoc:
|
|
14401
15633
|
end
|
14402
15634
|
end
|
14403
15635
|
|
15636
|
+
class W1026 < PassiveMessageDetection
|
15637
|
+
def initialize(context)
|
15638
|
+
super
|
15639
|
+
interp = context[:c_interpreter]
|
15640
|
+
interp.on_function_call_expr_evaled += method(:check)
|
15641
|
+
end
|
15642
|
+
|
15643
|
+
private
|
15644
|
+
def check(expression, function, arg_variables, *)
|
15645
|
+
arg_exprs = expression.argument_expressions
|
15646
|
+
arg_exprs.zip(arg_variables).each_with_index do |(expr, var), index|
|
15647
|
+
if var.type.incomplete?
|
15648
|
+
W(:W1026, expr.location, index + 1)
|
15649
|
+
end
|
15650
|
+
end
|
15651
|
+
end
|
15652
|
+
end
|
15653
|
+
|
14404
15654
|
class W1027 < PassiveMessageDetection
|
14405
15655
|
def initialize(context)
|
14406
15656
|
super
|
@@ -14584,6 +15834,103 @@ module C #:nodoc:
|
|
14584
15834
|
end
|
14585
15835
|
end
|
14586
15836
|
|
15837
|
+
class W1039 < PassiveMessageDetection
|
15838
|
+
def initialize(context)
|
15839
|
+
super
|
15840
|
+
interp = context[:c_interpreter]
|
15841
|
+
interp.on_function_call_expr_evaled += method(:check)
|
15842
|
+
@environ = interp.environment
|
15843
|
+
end
|
15844
|
+
|
15845
|
+
private
|
15846
|
+
def check(expression, function, arg_variables, *)
|
15847
|
+
if function.named?
|
15848
|
+
case function.name
|
15849
|
+
when /\A.*printf\z/
|
15850
|
+
check_printf_format(expression, arg_variables)
|
15851
|
+
when /\A.*scanf\z/
|
15852
|
+
check_scanf_format(expression, arg_variables)
|
15853
|
+
end
|
15854
|
+
end
|
15855
|
+
end
|
15856
|
+
|
15857
|
+
def check_printf_format(expression, arg_variables)
|
15858
|
+
if format = create_printf_format(expression, arg_variables)
|
15859
|
+
css = format.conversion_specifiers
|
15860
|
+
css.each_with_index do |cs, index|
|
15861
|
+
if cs.length_modifier == "ll"
|
15862
|
+
W(:W1039, format.location, index + 1)
|
15863
|
+
end
|
15864
|
+
end
|
15865
|
+
end
|
15866
|
+
end
|
15867
|
+
|
15868
|
+
def check_scanf_format(expression, arg_variables)
|
15869
|
+
if format = create_scanf_format(expression, arg_variables)
|
15870
|
+
css = format.conversion_specifiers
|
15871
|
+
css.each_with_index do |cs, index|
|
15872
|
+
if cs.length_modifier == "ll"
|
15873
|
+
W(:W1039, format.location, index + 1)
|
15874
|
+
end
|
15875
|
+
end
|
15876
|
+
end
|
15877
|
+
end
|
15878
|
+
|
15879
|
+
def create_printf_format(expression, arg_variables)
|
15880
|
+
if format_index = format_arg_index_of(expression)
|
15881
|
+
format_arg = expression.argument_expressions[format_index]
|
15882
|
+
if format_arg && format_arg.literal.value =~ /\AL?"(.*)"\z/i
|
15883
|
+
location = format_arg.location
|
15884
|
+
trailing_args = arg_variables[(format_index + 1)..-1] || []
|
15885
|
+
return PrintfFormat.new($1, location, trailing_args, @environ)
|
15886
|
+
end
|
15887
|
+
end
|
15888
|
+
nil
|
15889
|
+
end
|
15890
|
+
|
15891
|
+
def create_scanf_format(expression, arg_variables)
|
15892
|
+
if format_index = format_arg_index_of(expression)
|
15893
|
+
format_arg = expression.argument_expressions[format_index]
|
15894
|
+
if format_arg && format_arg.literal.value =~ /\AL?"(.*)"\z/i
|
15895
|
+
location = format_arg.location
|
15896
|
+
trailing_args = arg_variables[(format_index + 1)..-1] || []
|
15897
|
+
return ScanfFormat.new($1, location, trailing_args, @environ)
|
15898
|
+
end
|
15899
|
+
end
|
15900
|
+
nil
|
15901
|
+
end
|
15902
|
+
|
15903
|
+
def format_arg_index_of(function_call_expression)
|
15904
|
+
function_call_expression.argument_expressions.index do |arg_expr|
|
15905
|
+
arg_expr.kind_of?(StringLiteralSpecifier)
|
15906
|
+
end
|
15907
|
+
end
|
15908
|
+
end
|
15909
|
+
|
15910
|
+
class W1047 < PassiveMessageDetection
|
15911
|
+
include SyntaxNodeCollector
|
15912
|
+
|
15913
|
+
def initialize(context)
|
15914
|
+
super
|
15915
|
+
interp = context[:c_interpreter]
|
15916
|
+
interp.on_variable_initialized += method(:check)
|
15917
|
+
@enum_tbl = interp.environment.enumerator_table
|
15918
|
+
end
|
15919
|
+
|
15920
|
+
private
|
15921
|
+
def check(variable_definition, *)
|
15922
|
+
type = variable_definition.type
|
15923
|
+
if type.struct? || type.union? || type.array?
|
15924
|
+
if initializer = variable_definition.initializer
|
15925
|
+
obj_specs = collect_object_specifiers(initializer)
|
15926
|
+
if obj_specs.any? { |os| !@enum_tbl.lookup(os.identifier.value) }
|
15927
|
+
W(:W1047, variable_definition.location)
|
15928
|
+
end
|
15929
|
+
end
|
15930
|
+
end
|
15931
|
+
end
|
15932
|
+
end
|
15933
|
+
|
14587
15934
|
class W1049 < PassiveMessageDetection
|
14588
15935
|
def initialize(context)
|
14589
15936
|
super
|
@@ -15025,6 +16372,36 @@ module C #:nodoc:
|
|
15025
16372
|
end
|
15026
16373
|
end
|
15027
16374
|
|
16375
|
+
class W1071 < PassiveMessageDetection
|
16376
|
+
def initialize(context)
|
16377
|
+
super
|
16378
|
+
interp = context[:c_interpreter]
|
16379
|
+
interp.on_function_started += method(:enter_function)
|
16380
|
+
interp.on_function_ended += method(:leave_function)
|
16381
|
+
interp.on_implicit_return_evaled += method(:memorize_termination)
|
16382
|
+
interp.on_return_stmt_evaled += lambda { |*| memorize_termination }
|
16383
|
+
@current_function = nil
|
16384
|
+
end
|
16385
|
+
|
16386
|
+
private
|
16387
|
+
def enter_function(function_definition, *)
|
16388
|
+
@current_function = function_definition
|
16389
|
+
@termination_points = 0
|
16390
|
+
end
|
16391
|
+
|
16392
|
+
def leave_function(*)
|
16393
|
+
if @current_function && @termination_points > 1
|
16394
|
+
W(:W1071,
|
16395
|
+
@current_function.location, @current_function.identifier.value)
|
16396
|
+
end
|
16397
|
+
@current_function = nil
|
16398
|
+
end
|
16399
|
+
|
16400
|
+
def memorize_termination
|
16401
|
+
@termination_points += 1 if @current_function
|
16402
|
+
end
|
16403
|
+
end
|
16404
|
+
|
15028
16405
|
class W1073 < PassiveMessageDetection
|
15029
16406
|
def initialize(context)
|
15030
16407
|
super
|
@@ -15228,6 +16605,11 @@ module C #:nodoc:
|
|
15228
16605
|
from_type = original_variable.type
|
15229
16606
|
to_type = result_variable.type
|
15230
16607
|
|
16608
|
+
if from_type.undeclared? || from_type.unresolved? ||
|
16609
|
+
to_type.undeclared? || to_type.unresolved?
|
16610
|
+
return
|
16611
|
+
end
|
16612
|
+
|
15231
16613
|
unless from_type.standard? && to_type.standard?
|
15232
16614
|
unless from_type.convertible?(to_type)
|
15233
16615
|
W(:W9003, initializer_or_expression.location, from_type.brief_image)
|