adlint 1.2.0 → 1.4.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.
@@ -61,6 +61,10 @@ module C #:nodoc:
61
61
  ]
62
62
 
63
63
  @suppress_notification = false
64
+
65
+ # NOTE: Active (executing) function may be nested if the nested
66
+ # function-definition of the GCC extension is used.
67
+ @active_function_stack = []
64
68
  end
65
69
 
66
70
  attr_reader :environment
@@ -276,6 +280,13 @@ module C #:nodoc:
276
280
  :assignment_expression, :lhs_variable,
277
281
  :rhs_variable
278
282
 
283
+ # NOTE: Notified when the interpreter starts execution of a
284
+ # switch-statement.
285
+ def_plugin_and_notifier :switch_stmt_started, :switch_statement
286
+
287
+ # NOTE: Notified when the interpreter ends execution of a switch-statement.
288
+ def_plugin_and_notifier :switch_stmt_ended, :switch_statement
289
+
279
290
  # NOTE: Notified when the interpreter starts execution of a
280
291
  # while-statement.
281
292
  def_plugin_and_notifier :while_stmt_started, :while_statement
@@ -319,6 +330,16 @@ module C #:nodoc:
319
330
  def_plugin_and_notifier :if_else_ctrlexpr_evaled,
320
331
  :if_else_statement, :ctrlexpr_value
321
332
 
333
+ # NOTE: Notified when the interpreter evaluates a controlling expression of
334
+ # the switch-statement.
335
+ def_plugin_and_notifier :switch_ctrlexpr_evaled,
336
+ :switch_statement, :ctrlexpr_result
337
+
338
+ # NOTE: Notified when the interpreter evaluates a controlling expression of
339
+ # the case-labeled-statement.
340
+ def_plugin_and_notifier :case_ctrlexpr_evaled,
341
+ :case_labeled_statement, :ctrlexpr_result
342
+
322
343
  # NOTE: Notified when the interpreter evaluates a controlling expression of
323
344
  # the while-statement.
324
345
  def_plugin_and_notifier :while_ctrlexpr_evaled,
@@ -409,6 +430,24 @@ module C #:nodoc:
409
430
  @suppress_notification = suppress_notification
410
431
  end
411
432
 
433
+ def _active_function
434
+ # NOTE: This method is called only from
435
+ # StatementInterpreter#visit_return_statement.
436
+ # NOTE: To convert returning object, StatementInterpreter must have
437
+ # knowledge about conversion destination type.
438
+ @active_function_stack.last
439
+ end
440
+
441
+ def _enter_function(function_definition)
442
+ # NOTE: This method is called only from FunctionInterpreter.
443
+ @active_function_stack.push(function_definition)
444
+ end
445
+
446
+ def _leave_function(function_definition)
447
+ # NOTE: This method is called only from FunctionInterpreter.
448
+ @active_function_stack.pop
449
+ end
450
+
412
451
  private
413
452
  def interpreter_for(node)
414
453
  @sub_interpreters.find do |interp|
@@ -519,25 +558,14 @@ module C #:nodoc:
519
558
  end
520
559
 
521
560
  if initializer = node.initializer
522
- init_variable = evaluate_initializer(initializer, node.type)
523
-
524
- if node.type.same_as?(init_variable.type)
525
- converted = init_variable
526
- else
527
- converted =
528
- do_conversion(init_variable, node.type) ||
529
- temporary_variable(node.type)
530
- notify_implicit_conv_performed(initializer, init_variable, converted)
531
- end
561
+ init_variable, converted = evaluate_initializer(initializer, node.type)
562
+ variable = define_variable(node, converted.value.to_defined_value)
532
563
 
533
564
  notify_variable_value_referred(node, init_variable)
534
-
535
- variable = define_variable(node, converted.value.to_defined_value)
536
565
  notify_variable_defined(node, variable)
537
566
  notify_variable_initialized(node, variable, init_variable)
538
567
  else
539
- variable = define_variable(node)
540
- notify_variable_defined(node, variable)
568
+ notify_variable_defined(node, define_variable(node))
541
569
  end
542
570
 
543
571
  evaluate_sequence_point(node.init_declarator.declarator)
@@ -600,29 +628,21 @@ module C #:nodoc:
600
628
  private
601
629
  def evaluate_initializer(initializer, variable_type)
602
630
  init_interp = InitializerInterpreter.new(interpreter)
603
- object = init_interp.execute(initializer, variable_type)
631
+ variable, converted = init_interp.execute(initializer, variable_type)
604
632
 
605
- case
606
- when variable_type.pointer? && object.type.array?
607
- init_variable = temporary_variable(variable_type,
608
- pointer_value_of(object))
609
- notify_implicit_conv_performed(initializer, object, init_variable)
610
- when variable_type.pointer? && object.type.function?
611
- init_variable = temporary_variable(variable_type,
612
- pointer_value_of(object))
613
- notify_implicit_conv_performed(initializer, object, init_variable)
614
- when variable_type.array? && object.type.pointer?
615
- unless init_variable = pointee_of(object) and init_variable.type.array?
616
- init_variable = temporary_variable(variable_type)
633
+ # NOTE: An implicit conversion has been done by InitializerInterpreter.
634
+
635
+ # NOTE: For the case of array variable definition with a
636
+ # string-literal-specifier as the initializer.
637
+ if variable_type.array? && variable.type.pointer?
638
+ unless array = pointee_of(variable) and array.type.array?
639
+ array = temporary_variable(variable_type)
617
640
  end
618
- deduct_array_length_from_array_variable(variable_type, init_variable)
619
- when object.function?
620
- init_variable = temporary_variable(variable_type)
621
- else
622
- init_variable = object
641
+ deduct_array_length_from_array_variable(variable_type, array)
642
+ variable = converted = array
623
643
  end
624
644
 
625
- init_variable
645
+ return variable, converted
626
646
  end
627
647
 
628
648
  def deduct_array_length_from_array_variable(variable_type, array_variable)
@@ -638,6 +658,8 @@ module C #:nodoc:
638
658
 
639
659
  class InitializerInterpreter
640
660
  include InterpreterMediator
661
+ include NotifierMediator
662
+ include Conversion
641
663
  include MonitorUtil
642
664
 
643
665
  def initialize(interpreter)
@@ -649,19 +671,46 @@ module C #:nodoc:
649
671
 
650
672
  case
651
673
  when expression = initializer.expression
652
- evaluate_expression(expression)
674
+ # NOTE: An implicit conversion is already notified in
675
+ # #evaluate_expression.
676
+ return evaluate_expression(expression, variable_type)
653
677
  when initializers = initializer.initializers
654
- evaluate_initializers(initializers, variable_type)
678
+ variable = evaluate_initializers(initializers, variable_type)
679
+
680
+ if variable.type.same_as?(variable_type)
681
+ converted = variable
682
+ else
683
+ converted =
684
+ do_conversion(variable, variable_type) ||
685
+ temporary_variable(variable_type)
686
+ notify_implicit_conv_performed(initializer, variable, converted)
687
+ end
655
688
  else
656
- temporary_variable(variable_type)
689
+ variable = converted = temporary_variable(variable_type)
657
690
  end
691
+
692
+ return variable, converted
658
693
  end
659
694
 
660
695
  private
661
- def evaluate_expression(expression)
696
+ def evaluate_expression(expression, type)
662
697
  checkpoint(expression.location)
663
698
 
664
- object_to_variable(interpret(expression))
699
+ object = interpret(expression)
700
+
701
+ variable = object_to_variable(object)
702
+ unless variable == object
703
+ notify_implicit_conv_performed(expression, object, variable)
704
+ end
705
+
706
+ if variable.type.same_as?(type)
707
+ converted = variable
708
+ else
709
+ converted = do_conversion(variable, type) || temporary_variable(type)
710
+ notify_implicit_conv_performed(expression, variable, converted)
711
+ end
712
+
713
+ return variable, converted
665
714
  end
666
715
 
667
716
  def evaluate_initializers(initializers, variable_type)
@@ -680,7 +729,7 @@ module C #:nodoc:
680
729
  checkpoint(initializer.location)
681
730
  case
682
731
  when expression = initializer.expression
683
- value_of(evaluate_expression(expression))
732
+ value_of(evaluate_expression(expression, type).last)
684
733
  when initializers = initializer.initializers
685
734
  value_of(evaluate_initializers(initializers, type))
686
735
  else
@@ -756,6 +805,8 @@ module C #:nodoc:
756
805
  def interpret_function(node)
757
806
  checkpoint(node.location)
758
807
 
808
+ interpreter._enter_function(node)
809
+
759
810
  reset_environment
760
811
  resolve_unresolved_type(node)
761
812
 
@@ -781,6 +832,8 @@ module C #:nodoc:
781
832
  notify_block_ended(node.function_body)
782
833
  notify_function_ended(node)
783
834
  end
835
+ ensure
836
+ interpreter._leave_function(node)
784
837
  end
785
838
  end
786
839
 
@@ -807,6 +860,11 @@ module C #:nodoc:
807
860
  checkpoint(node.location)
808
861
 
809
862
  node.executed = true
863
+ ctrlexpr = node.expression
864
+ ctrlexpr_result = object_to_variable(interpret(ctrlexpr,
865
+ :suppress_notification))
866
+ notify_case_ctrlexpr_evaled(node, ctrlexpr_result)
867
+
810
868
  interpret(node.statement)
811
869
  end
812
870
 
@@ -1025,7 +1083,7 @@ module C #:nodoc:
1025
1083
  interpret(node.body_statement)
1026
1084
  interpret(node.expression) if node.expression
1027
1085
  # NOTE: To avoid that value of the controlling variable is marked
1028
- # as updated at end of the for-statement. Value of the
1086
+ # as updated at end of the c99-for-statement. Value of the
1029
1087
  # controlling variable is referred by the controlling
1030
1088
  # expression at the last iteration.
1031
1089
  # FIXME: This re-interpretation of the controlling expression may
@@ -1038,7 +1096,7 @@ module C #:nodoc:
1038
1096
  interpret(node.body_statement)
1039
1097
  interpret(node.expression) if node.expression
1040
1098
  # NOTE: To avoid that value of the controlling variable is marked
1041
- # as updated at end of the for-statement. Value of the
1099
+ # as updated at end of the c99-for-statement. Value of the
1042
1100
  # controlling variable is referred by the controlling
1043
1101
  # expression at the last iteration.
1044
1102
  # FIXME: This re-interpretation of the controlling expression may
@@ -1084,8 +1142,35 @@ module C #:nodoc:
1084
1142
  checkpoint(node.location)
1085
1143
 
1086
1144
  node.executed = true
1087
- return_object = node.expression ? interpret(node.expression) : nil
1088
- notify_return_stmt_evaled(node, return_object)
1145
+
1146
+ unless node.expression
1147
+ notify_return_stmt_evaled(node, nil)
1148
+ BreakEvent.of_return.throw
1149
+ end
1150
+
1151
+ object = interpret(node.expression)
1152
+ variable = object_to_variable(object)
1153
+ unless variable == object
1154
+ notify_implicit_conv_performed(node.expression, object, variable)
1155
+ end
1156
+
1157
+ notify_variable_value_referred(node.expression, variable)
1158
+
1159
+ if active_function = interpreter._active_function and
1160
+ return_type = active_function.type.return_type
1161
+ if variable.type.same_as?(return_type)
1162
+ converted = variable
1163
+ else
1164
+ converted =
1165
+ do_conversion(variable, return_type) ||
1166
+ temporary_variable(return_type)
1167
+ notify_implicit_conv_performed(node.expression, variable, converted)
1168
+ end
1169
+ else
1170
+ converted = variable
1171
+ end
1172
+
1173
+ notify_return_stmt_evaled(node, variable)
1089
1174
  BreakEvent.of_return.throw
1090
1175
  end
1091
1176
 
@@ -1225,8 +1310,15 @@ module C #:nodoc:
1225
1310
  checkpoint(node.location)
1226
1311
 
1227
1312
  node.executed = true
1228
- object = interpret(node.expression)
1229
- execute_switch_body(object, node.statement) if object.variable?
1313
+ notify_switch_stmt_started(node)
1314
+
1315
+ ctrlexpr = node.expression
1316
+ ctrlexpr_result = object_to_variable(interpret(ctrlexpr))
1317
+ notify_switch_ctrlexpr_evaled(node, ctrlexpr_result)
1318
+
1319
+ execute_switch_body(ctrlexpr_result, node.statement)
1320
+
1321
+ notify_switch_stmt_ended(node)
1230
1322
  end
1231
1323
 
1232
1324
  private
@@ -217,6 +217,8 @@ module C #:nodoc:
217
217
  def_delegator :interpreter, :notify_prefix_decrement_expr_evaled
218
218
  def_delegator :interpreter, :notify_postfix_decrement_expr_evaled
219
219
  def_delegator :interpreter, :notify_assignment_expr_evaled
220
+ def_delegator :interpreter, :notify_switch_stmt_started
221
+ def_delegator :interpreter, :notify_switch_stmt_ended
220
222
  def_delegator :interpreter, :notify_while_stmt_started
221
223
  def_delegator :interpreter, :notify_while_stmt_ended
222
224
  def_delegator :interpreter, :notify_do_stmt_started
@@ -229,6 +231,8 @@ module C #:nodoc:
229
231
  def_delegator :interpreter, :notify_return_stmt_evaled
230
232
  def_delegator :interpreter, :notify_if_ctrlexpr_evaled
231
233
  def_delegator :interpreter, :notify_if_else_ctrlexpr_evaled
234
+ def_delegator :interpreter, :notify_switch_ctrlexpr_evaled
235
+ def_delegator :interpreter, :notify_case_ctrlexpr_evaled
232
236
  def_delegator :interpreter, :notify_while_ctrlexpr_evaled
233
237
  def_delegator :interpreter, :notify_do_ctrlexpr_evaled
234
238
  def_delegator :interpreter, :notify_for_ctrlexpr_evaled
@@ -6957,13 +6957,7 @@ module C #:nodoc:
6957
6957
 
6958
6958
  private
6959
6959
  def check_function(node)
6960
- if declaration_specifiers = node.declaration_specifiers
6961
- if declaration_specifiers.type_specifiers.empty?
6962
- W(:W0457, node.location)
6963
- end
6964
- else
6965
- W(:W0457, node.location)
6966
- end
6960
+ W(:W0457, node.location) if node.implicitly_typed?
6967
6961
  end
6968
6962
  end
6969
6963
 
@@ -6978,13 +6972,7 @@ module C #:nodoc:
6978
6972
 
6979
6973
  private
6980
6974
  def check_variable(node)
6981
- if declaration_specifiers = node.declaration_specifiers
6982
- if declaration_specifiers.type_specifiers.empty?
6983
- W(:W0458, node.location)
6984
- end
6985
- else
6986
- W(:W0458, node.location)
6987
- end
6975
+ W(:W0458, node.location) if node.implicitly_typed?
6988
6976
  end
6989
6977
  end
6990
6978
 
@@ -12279,6 +12267,260 @@ module C #:nodoc:
12279
12267
  private_constant :Visitor
12280
12268
  end
12281
12269
 
12270
+ class W0720 < PassiveMessageDetection
12271
+ def initialize(context)
12272
+ super
12273
+ interp = context[:c_interpreter]
12274
+ interp.on_explicit_conv_performed += method(:check)
12275
+ end
12276
+
12277
+ private
12278
+ def check(expression, original_variable, result_variable)
12279
+ orig_type = original_variable.type
12280
+ conv_type = result_variable.type
12281
+
12282
+ unless orig_type.scalar? && orig_type.floating? &&
12283
+ conv_type.scalar? && conv_type.integer?
12284
+ return
12285
+ end
12286
+
12287
+ orig_value = original_variable.value
12288
+ return unless orig_value.scalar?
12289
+
12290
+ lower_test = orig_value < ScalarValue.of(conv_type.min_value - 1)
12291
+ upper_test = orig_value > ScalarValue.of(conv_type.max_value + 1)
12292
+
12293
+ if lower_test.must_be_true? || upper_test.must_be_true?
12294
+ W(:W0720, expression.location)
12295
+ end
12296
+ end
12297
+ end
12298
+
12299
+ class W0721 < PassiveMessageDetection
12300
+ def initialize(context)
12301
+ super
12302
+ interp = context[:c_interpreter]
12303
+ interp.on_explicit_conv_performed += method(:check)
12304
+ end
12305
+
12306
+ private
12307
+ def check(expression, original_variable, result_variable)
12308
+ orig_type = original_variable.type
12309
+ conv_type = result_variable.type
12310
+
12311
+ unless orig_type.pointer? && conv_type.scalar? && conv_type.integer?
12312
+ return
12313
+ end
12314
+
12315
+ if orig_type.min_value < conv_type.min_value ||
12316
+ orig_type.max_value > conv_type.max_value
12317
+ W(:W0721, expression.location)
12318
+ end
12319
+ end
12320
+ end
12321
+
12322
+ class W0722 < PassiveMessageDetection
12323
+ def initialize(context)
12324
+ super
12325
+ interp = context[:c_interpreter]
12326
+ interp.on_multiplicative_expr_evaled += method(:check)
12327
+ interp.on_additive_expr_evaled += method(:check)
12328
+ end
12329
+
12330
+ private
12331
+ def check(binary_expression, lhs_variable, rhs_variable, result_variable)
12332
+ return unless lhs_variable.type.scalar? && lhs_variable.type.signed?
12333
+ return unless rhs_variable.type.scalar? && rhs_variable.type.signed?
12334
+
12335
+ return unless lhs_variable.value.scalar? && rhs_variable.value.scalar?
12336
+
12337
+ case binary_expression.operator.type
12338
+ when "+"
12339
+ unbound_value = lhs_variable.value + rhs_variable.value
12340
+ when "-"
12341
+ unbound_value = lhs_variable.value - rhs_variable.value
12342
+ when "*"
12343
+ unbound_value = lhs_variable.value * rhs_variable.value
12344
+ else
12345
+ return
12346
+ end
12347
+
12348
+ result_type = result_variable.type
12349
+ lower_test = unbound_value < ScalarValue.of(result_type.min_value)
12350
+ upper_test = unbound_value > ScalarValue.of(result_type.max_value)
12351
+
12352
+ if lower_test.must_be_true? || upper_test.must_be_true?
12353
+ W(:W0722, binary_expression.location)
12354
+ end
12355
+ end
12356
+ end
12357
+
12358
+ class W0723 < PassiveMessageDetection
12359
+ def initialize(context)
12360
+ super
12361
+ interp = context[:c_interpreter]
12362
+ interp.on_multiplicative_expr_evaled += method(:check)
12363
+ interp.on_additive_expr_evaled += method(:check)
12364
+ end
12365
+
12366
+ private
12367
+ def check(binary_expression, lhs_variable, rhs_variable, result_variable)
12368
+ return unless lhs_variable.type.scalar? && lhs_variable.type.signed?
12369
+ return unless rhs_variable.type.scalar? && rhs_variable.type.signed?
12370
+
12371
+ return unless lhs_variable.value.scalar? && rhs_variable.value.scalar?
12372
+
12373
+ case binary_expression.operator.type
12374
+ when "+"
12375
+ unbound_value = lhs_variable.value + rhs_variable.value
12376
+ when "-"
12377
+ unbound_value = lhs_variable.value + rhs_variable.value
12378
+ when "*"
12379
+ unbound_value = lhs_variable.value * rhs_variable.value
12380
+ else
12381
+ return
12382
+ end
12383
+
12384
+ result_type = result_variable.type
12385
+ lower_test = unbound_value < ScalarValue.of(result_type.min_value)
12386
+ upper_test = unbound_value > ScalarValue.of(result_type.max_value)
12387
+
12388
+ if !lower_test.must_be_true? && lower_test.may_be_true? or
12389
+ !upper_test.must_be_true? && upper_test.may_be_true?
12390
+ W(:W0723, binary_expression.location)
12391
+ end
12392
+ end
12393
+ end
12394
+
12395
+ class W0727 < PassiveMessageDetection
12396
+ def initialize(context)
12397
+ super
12398
+ interp = context[:c_interpreter]
12399
+ interp.on_explicit_conv_performed += method(:check)
12400
+ interp.on_implicit_conv_performed += method(:check)
12401
+ end
12402
+
12403
+ private
12404
+ def check(initializer_or_expression, original_variable, result_variable)
12405
+ return unless result_variable.type.enum?
12406
+
12407
+ value = original_variable.value.unique_sample
12408
+
12409
+ unless result_variable.type.enumerators.any? { |enum| value == enum.value }
12410
+ W(:W0727, initializer_or_expression.location)
12411
+ end
12412
+ end
12413
+ end
12414
+
12415
+ class W0728 < PassiveMessageDetection
12416
+ def initialize(context)
12417
+ super
12418
+ interp = context[:c_interpreter]
12419
+ interp.on_function_call_expr_evaled += method(:check)
12420
+ end
12421
+
12422
+ private
12423
+ def check(expression, function, arg_variables, result_variable)
12424
+ args = arg_variables.zip(function.type.parameter_types)
12425
+ args.each_with_index do |(arg_variable, param_type), index|
12426
+ next unless param_type && param_type.enum?
12427
+
12428
+ if arg_variable.type.enum?
12429
+ unless arg_variable.type.same_as?(param_type)
12430
+ W(:W0728, expression.argument_expressions[index].location)
12431
+ end
12432
+ end
12433
+ end
12434
+ end
12435
+ end
12436
+
12437
+ class W0729 < PassiveMessageDetection
12438
+ def initialize(context)
12439
+ super
12440
+ interp = context[:c_interpreter]
12441
+ interp.on_assignment_expr_evaled += method(:check)
12442
+ end
12443
+
12444
+ private
12445
+ def check(expression, lhs_variable, rhs_variable)
12446
+ return unless lhs_variable.type.enum?
12447
+
12448
+ if rhs_variable.type.enum?
12449
+ unless lhs_variable.type.same_as?(rhs_variable.type)
12450
+ W(:W0729, expression.location)
12451
+ end
12452
+ end
12453
+ end
12454
+ end
12455
+
12456
+ class W0730 < PassiveMessageDetection
12457
+ def initialize(context)
12458
+ super
12459
+ interp = context[:c_interpreter]
12460
+ interp.on_function_started += method(:start_function)
12461
+ interp.on_function_ended += method(:end_function)
12462
+ interp.on_return_stmt_evaled += method(:check)
12463
+ @current_function = nil
12464
+ end
12465
+
12466
+ private
12467
+ def start_function(function_definition)
12468
+ @current_function = function_definition
12469
+ end
12470
+
12471
+ def end_function(function_definition)
12472
+ @current_function = nil
12473
+ end
12474
+
12475
+ def check(return_statement, result_variable)
12476
+ return unless @current_function && result_variable
12477
+
12478
+ return unless return_type = @current_function.type.return_type
12479
+ return unless return_type.enum?
12480
+
12481
+ if result_variable.type.enum?
12482
+ unless return_type.same_as?(result_variable.type)
12483
+ W(:W0730, return_statement.expression.location)
12484
+ end
12485
+ end
12486
+ end
12487
+ end
12488
+
12489
+ class W0731 < PassiveMessageDetection
12490
+ def initialize(context)
12491
+ super
12492
+ interp = context[:c_interpreter]
12493
+ interp.on_switch_stmt_ended += method(:end_switch_statement)
12494
+ interp.on_switch_ctrlexpr_evaled += method(:memorize_switch_ctrlexpr)
12495
+ interp.on_case_ctrlexpr_evaled += method(:check)
12496
+ @switch_ctrlexpr_stack = []
12497
+ end
12498
+
12499
+ private
12500
+ def end_switch_statement(node)
12501
+ @switch_ctrlexpr_stack.pop
12502
+ end
12503
+
12504
+ def memorize_switch_ctrlexpr(node, ctrlexpr_result)
12505
+ @switch_ctrlexpr_stack.push(ctrlexpr_result)
12506
+ end
12507
+
12508
+ def check(case_labeled_statement, ctrlexpr_result)
12509
+ unless switch_ctrlexpr_result = @switch_ctrlexpr_stack.last
12510
+ return
12511
+ end
12512
+
12513
+ return unless switch_ctrlexpr_result.type.enum?
12514
+ expected_type = switch_ctrlexpr_result.type
12515
+
12516
+ value = ctrlexpr_result.value.unique_sample
12517
+ unless expected_type.enumerators.any? { |enum| value == enum.value }
12518
+ W(:W0731, case_labeled_statement.expression.location,
12519
+ case_labeled_statement.expression.to_s)
12520
+ end
12521
+ end
12522
+ end
12523
+
12282
12524
  class W0736 < PassiveMessageDetection
12283
12525
  def initialize(context)
12284
12526
  super
@@ -12328,6 +12570,146 @@ module C #:nodoc:
12328
12570
  end
12329
12571
  end
12330
12572
 
12573
+ class W0737 < PassiveMessageDetection
12574
+ def initialize(context)
12575
+ super
12576
+ interp = context[:c_interpreter]
12577
+ interp.on_variable_declared += method(:check)
12578
+ interp.on_variable_defined += method(:check)
12579
+ end
12580
+
12581
+ private
12582
+ def check(decl_or_def, variable)
12583
+ return unless decl_or_def.type.enum?
12584
+
12585
+ if decl_or_def.type.incomplete?
12586
+ W(:W0737, decl_or_def.location, decl_or_def.type.name)
12587
+ end
12588
+ end
12589
+ end
12590
+
12591
+ class W0738 < PassiveMessageDetection
12592
+ def initialize(context)
12593
+ super
12594
+ interp = context[:c_interpreter]
12595
+ interp.on_implicit_conv_performed += method(:check)
12596
+ end
12597
+
12598
+ private
12599
+ def check(initializer_or_expression, original_variable, result_variable)
12600
+ case initializer_or_expression
12601
+ when Initializer
12602
+ unless expression = initializer_or_expression.expression
12603
+ return
12604
+ end
12605
+ when Expression
12606
+ expression = initializer_or_expression
12607
+ end
12608
+
12609
+ return unless expression.constant?
12610
+
12611
+ orig_type = original_variable.type
12612
+ conv_type = result_variable.type
12613
+
12614
+ unless orig_type.scalar? && orig_type.integer? &&
12615
+ conv_type.scalar? && conv_type.integer? && conv_type.unsigned?
12616
+ return
12617
+ end
12618
+
12619
+ orig_value = original_variable.value
12620
+ return unless orig_value.scalar?
12621
+
12622
+ upper_test = orig_value > ScalarValue.of(conv_type.max_value)
12623
+
12624
+ W(:W0738, expression.location) if upper_test.must_be_true?
12625
+ end
12626
+ end
12627
+
12628
+ class W0739 < PassiveMessageDetection
12629
+ def initialize(context)
12630
+ super
12631
+ interp = context[:c_interpreter]
12632
+ interp.on_additive_expr_evaled += method(:check)
12633
+ end
12634
+
12635
+ private
12636
+ def check(additive_expression, lhs_variable, rhs_variable, result_variable)
12637
+ return unless additive_expression.operator.type == "-"
12638
+
12639
+ return unless additive_expression.lhs_operand.constant?
12640
+ return unless additive_expression.rhs_operand.constant?
12641
+
12642
+ return unless lhs_variable.type.scalar? && lhs_variable.type.unsigned?
12643
+ return unless rhs_variable.type.scalar? && rhs_variable.type.unsigned?
12644
+
12645
+ return unless lhs_variable.value.scalar? && rhs_variable.value.scalar?
12646
+
12647
+ unbound_value = lhs_variable.value - rhs_variable.value
12648
+
12649
+ result_type = result_variable.type
12650
+ lower_test = unbound_value < ScalarValue.of(result_type.min_value)
12651
+
12652
+ W(:W0739, additive_expression.location) if lower_test.must_be_true?
12653
+ end
12654
+ end
12655
+
12656
+ class W0740 < PassiveMessageDetection
12657
+ def initialize(context)
12658
+ super
12659
+ interp = context[:c_interpreter]
12660
+ interp.on_additive_expr_evaled += method(:check)
12661
+ end
12662
+
12663
+ private
12664
+ def check(additive_expression, lhs_variable, rhs_variable, result_variable)
12665
+ return unless additive_expression.operator.type == "+"
12666
+
12667
+ return unless additive_expression.lhs_operand.constant?
12668
+ return unless additive_expression.rhs_operand.constant?
12669
+
12670
+ return unless lhs_variable.type.scalar? && lhs_variable.type.unsigned?
12671
+ return unless rhs_variable.type.scalar? && rhs_variable.type.unsigned?
12672
+
12673
+ return unless lhs_variable.value.scalar? && rhs_variable.value.scalar?
12674
+
12675
+ unbound_value = lhs_variable.value + rhs_variable.value
12676
+
12677
+ result_type = result_variable.type
12678
+ upper_test = unbound_value > ScalarValue.of(result_type.max_value)
12679
+
12680
+ W(:W0740, additive_expression.location) if upper_test.must_be_true?
12681
+ end
12682
+ end
12683
+
12684
+ class W0741 < PassiveMessageDetection
12685
+ def initialize(context)
12686
+ super
12687
+ interp = context[:c_interpreter]
12688
+ interp.on_multiplicative_expr_evaled += method(:check)
12689
+ end
12690
+
12691
+ private
12692
+ def check(multiplicative_expression, lhs_variable, rhs_variable,
12693
+ result_variable)
12694
+ return unless multiplicative_expression.operator.type == "*"
12695
+
12696
+ return unless multiplicative_expression.lhs_operand.constant?
12697
+ return unless multiplicative_expression.rhs_operand.constant?
12698
+
12699
+ return unless lhs_variable.type.scalar? && lhs_variable.type.unsigned?
12700
+ return unless rhs_variable.type.scalar? && rhs_variable.type.unsigned?
12701
+
12702
+ return unless lhs_variable.value.scalar? && rhs_variable.value.scalar?
12703
+
12704
+ unbound_value = lhs_variable.value * rhs_variable.value
12705
+
12706
+ result_type = result_variable.type
12707
+ upper_test = unbound_value > ScalarValue.of(result_type.max_value)
12708
+
12709
+ W(:W0741, multiplicative_expression.location) if upper_test.must_be_true?
12710
+ end
12711
+ end
12712
+
12331
12713
  class W0742 < PassiveMessageDetection
12332
12714
  def initialize(context)
12333
12715
  super
@@ -12355,6 +12737,46 @@ module C #:nodoc:
12355
12737
  end
12356
12738
  end
12357
12739
 
12740
+ class W0743 < PassiveMessageDetection
12741
+ def initialize(context)
12742
+ super
12743
+ interp = context[:c_interpreter]
12744
+ interp.on_implicit_conv_performed += method(:check)
12745
+ end
12746
+
12747
+ private
12748
+ def check(initializer_or_expression, original_variable, result_variable)
12749
+ case initializer_or_expression
12750
+ when Initializer
12751
+ unless expression = initializer_or_expression.expression
12752
+ return
12753
+ end
12754
+ when Expression
12755
+ expression = initializer_or_expression
12756
+ end
12757
+
12758
+ return unless expression.constant?
12759
+
12760
+ orig_type = original_variable.type
12761
+ conv_type = result_variable.type
12762
+
12763
+ unless orig_type.scalar? && orig_type.integer? &&
12764
+ conv_type.scalar? && conv_type.integer? && conv_type.signed?
12765
+ return
12766
+ end
12767
+
12768
+ orig_value = original_variable.value
12769
+ return unless orig_value.scalar?
12770
+
12771
+ lower_test = orig_value < ScalarValue.of(conv_type.min_value)
12772
+ upper_test = orig_value > ScalarValue.of(conv_type.max_value)
12773
+
12774
+ if lower_test.must_be_true? || upper_test.must_be_true?
12775
+ W(:W0743, expression.location)
12776
+ end
12777
+ end
12778
+ end
12779
+
12358
12780
  class W0744 < PassiveMessageDetection
12359
12781
  def initialize(context)
12360
12782
  super
@@ -13593,7 +14015,11 @@ module C #:nodoc:
13593
14015
  def check(expression, original_variable, result_variable)
13594
14016
  orig_type = original_variable.type
13595
14017
  conv_type = result_variable.type
13596
- return unless orig_type.scalar? && conv_type.scalar? && conv_type.signed?
14018
+
14019
+ unless orig_type.scalar? && orig_type.integer? &&
14020
+ conv_type.scalar? && conv_type.integer? && conv_type.signed?
14021
+ return
14022
+ end
13597
14023
 
13598
14024
  orig_value = original_variable.value
13599
14025
  return unless orig_value.scalar?
@@ -13619,7 +14045,11 @@ module C #:nodoc:
13619
14045
  def check(expression, original_variable, result_variable)
13620
14046
  orig_type = original_variable.type
13621
14047
  conv_type = result_variable.type
13622
- return unless orig_type.scalar? && conv_type.scalar? && conv_type.signed?
14048
+
14049
+ unless orig_type.scalar? && orig_type.integer? &&
14050
+ conv_type.scalar? && conv_type.integer? && conv_type.signed?
14051
+ return
14052
+ end
13623
14053
 
13624
14054
  orig_value = original_variable.value
13625
14055
  return unless orig_value.scalar?
@@ -13706,6 +14136,39 @@ module C #:nodoc:
13706
14136
  end
13707
14137
  end
13708
14138
 
14139
+ class W1064 < W0731
14140
+ private
14141
+ def check(case_labeled_statement, ctrlexpr_result)
14142
+ unless switch_ctrlexpr_result = @switch_ctrlexpr_stack.last
14143
+ return
14144
+ end
14145
+
14146
+ return unless switch_ctrlexpr_result.type.enum?
14147
+
14148
+ unless ctrlexpr_result.type.enum?
14149
+ W(:W1064, case_labeled_statement.expression.location)
14150
+ end
14151
+ end
14152
+ end
14153
+
14154
+ class W1065 < W0731
14155
+ private
14156
+ def check(case_labeled_statement, ctrlexpr_result)
14157
+ unless switch_ctrlexpr_result = @switch_ctrlexpr_stack.last
14158
+ return
14159
+ end
14160
+
14161
+ return unless switch_ctrlexpr_result.type.enum?
14162
+ expected_type = switch_ctrlexpr_result.type
14163
+
14164
+ if ctrlexpr_result.type.enum?
14165
+ unless ctrlexpr_result.type.same_as?(expected_type)
14166
+ W(:W1065, case_labeled_statement.expression.location)
14167
+ end
14168
+ end
14169
+ end
14170
+ end
14171
+
13709
14172
  class W9001 < PassiveMessageDetection
13710
14173
  def initialize(context)
13711
14174
  super