adlint 1.16.0 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|