adlint 2.4.10 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/adlint/c/type.rb CHANGED
@@ -5080,7 +5080,7 @@ module C #:nodoc:
5080
5080
  rhs_base = rhs_unqualified.base_type
5081
5081
 
5082
5082
  unless lhs_base.more_cv_qualified?(rhs_base)
5083
- lhs_base.void? || lhs_base.convertible?(rhs_base)
5083
+ rhs_base.void? || lhs_base.convertible?(rhs_base)
5084
5084
  else
5085
5085
  false
5086
5086
  end
@@ -5555,7 +5555,7 @@ module C #:nodoc:
5555
5555
  rhs_base = rhs_unqualified.base_type
5556
5556
 
5557
5557
  unless lhs_base.more_cv_qualified?(rhs_base)
5558
- lhs_base.convertible?(rhs_base)
5558
+ rhs_base.void? || lhs_base.convertible?(rhs_base)
5559
5559
  else
5560
5560
  false
5561
5561
  end
@@ -6741,7 +6741,11 @@ module C #:nodoc:
6741
6741
  extend Forwardable
6742
6742
 
6743
6743
  def_delegator :@base_type, :image
6744
- def_delegator :@base_type, :brief_image
6744
+
6745
+ def brief_image
6746
+ name
6747
+ end
6748
+
6745
6749
  def_delegator :@base_type, :bit_size
6746
6750
  def_delegator :@base_type, :bit_alignment
6747
6751
  def_delegator :@base_type, :real_type
@@ -6911,6 +6915,8 @@ module C #:nodoc:
6911
6915
  def_delegator :@type, :incomplete?
6912
6916
  def_delegator :@type, :compatible?
6913
6917
  def_delegator :@type, :coercible?
6918
+ def_delegator :@type, :convertible?
6919
+ def_delegator :@type, :more_cv_qualified?
6914
6920
 
6915
6921
  def parameter?
6916
6922
  true
@@ -6942,6 +6948,7 @@ module C #:nodoc:
6942
6948
  def_delegator :@type, :parameter_types
6943
6949
  def_delegator :@type, :enumerators
6944
6950
  def_delegator :@type, :length
6951
+ def_delegator :@type, :length=
6945
6952
  def_delegator :@type, :impl_length
6946
6953
  def_delegator :@type, :members
6947
6954
  def_delegator :@type, :member_named
@@ -39,6 +39,7 @@ require "adlint/c/syntax"
39
39
  require "adlint/c/type"
40
40
  require "adlint/c/format"
41
41
  require "adlint/c/option"
42
+ require "adlint/c/conv"
42
43
  require "adlint/c/util"
43
44
  require "adlint/cpp/syntax"
44
45
 
@@ -1818,29 +1819,34 @@ module CBuiltin #:nodoc:
1818
1819
 
1819
1820
  def initialize(context)
1820
1821
  super
1821
- visitor = context[:c_visitor]
1822
- visitor.enter_expression_statement += method(:enter_expression_statement)
1823
- visitor.leave_expression_statement += method(:leave_expression_statement)
1824
- visitor.enter_logical_and_expression += method(:check)
1825
- visitor.enter_logical_or_expression += method(:check)
1826
- @in_expression_statement = false
1822
+ interp = context[:c_interpreter]
1823
+ interp.on_expression_stmt_started += method(:enter_expression_statement)
1824
+ interp.on_expression_stmt_ended += method(:leave_expression_statement)
1825
+ interp.on_logical_and_expr_evaled += method(:check)
1826
+ interp.on_logical_or_expr_evaled += method(:check)
1827
+ @current_expr_stmt = nil
1827
1828
  end
1828
1829
 
1829
1830
  private
1830
- def enter_expression_statement(node)
1831
- @in_expression_statement = true
1831
+ def enter_expression_statement(expr_stmt)
1832
+ case expr_stmt.expression
1833
+ when C::SimpleAssignmentExpression, C::CompoundAssignmentExpression,
1834
+ C::FunctionCallExpression
1835
+ @current_expr_stmt = nil
1836
+ else
1837
+ @current_expr_stmt = expr_stmt
1838
+ end
1832
1839
  end
1833
1840
 
1834
- def leave_expression_statement(node)
1835
- @in_expression_statement = false
1841
+ def leave_expression_statement(*)
1842
+ @current_expr_stmt = nil
1836
1843
  end
1837
1844
 
1838
- def check(node)
1839
- if @in_expression_statement
1840
- unless node.rhs_operand.have_side_effect?
1841
- W(:W0088, node.operator.location)
1845
+ def check(binary_expr, *)
1846
+ if @current_expr_stmt
1847
+ unless binary_expr.rhs_operand.have_side_effect?
1848
+ W(:W0088, binary_expr.operator.location)
1842
1849
  end
1843
- @in_expression_statement = false
1844
1850
  end
1845
1851
  end
1846
1852
  end
@@ -2023,7 +2029,7 @@ module CBuiltin #:nodoc:
2023
2029
  if rhs_pointee = @interp.pointee_of(rhs_variable)
2024
2030
  if rhs_pointee.variable? && rhs_pointee.named?
2025
2031
  return unless rhs_pointee.binding.memory.dynamic?
2026
- # NOTE: An array typed parameter can be considerd as an alias of the
2032
+ # NOTE: An array typed parameter can be considered as an alias of the
2027
2033
  # corresponding argument. So, it is safe to return an address
2028
2034
  # of the argument.
2029
2035
  return if rhs_pointee.type.parameter? && rhs_pointee.type.array?
@@ -2092,7 +2098,7 @@ module CBuiltin #:nodoc:
2092
2098
  if rhs_pointee = @interp.pointee_of(rhs_variable)
2093
2099
  if rhs_pointee.variable? && rhs_pointee.named?
2094
2100
  return unless rhs_pointee.binding.memory.dynamic?
2095
- # NOTE: An array typed parameter can be considerd as an alias of the
2101
+ # NOTE: An array typed parameter can be considered as an alias of the
2096
2102
  # corresponding argument. So, it is safe to return an address
2097
2103
  # of the argument.
2098
2104
  return if rhs_pointee.type.parameter? && rhs_pointee.type.array?
@@ -2140,7 +2146,7 @@ module CBuiltin #:nodoc:
2140
2146
 
2141
2147
  if pointee = @interp.pointee_of(result_variable)
2142
2148
  if pointee.variable? && pointee.named?
2143
- # NOTE: An array typed parameter can be considerd as an alias of the
2149
+ # NOTE: An array typed parameter can be considered as an alias of the
2144
2150
  # corresponding argument. So, it is safe to return an address
2145
2151
  # of the argument.
2146
2152
  return if pointee.type.parameter? && pointee.type.array?
@@ -2290,7 +2296,7 @@ module CBuiltin #:nodoc:
2290
2296
  if rhs_pointee = @interp.pointee_of(rhs_variable)
2291
2297
  if rhs_pointee.variable? && rhs_pointee.named?
2292
2298
  return unless rhs_pointee.binding.memory.dynamic?
2293
- # NOTE: An array typed parameter can be considerd as an alias of the
2299
+ # NOTE: An array typed parameter can be considered as an alias of the
2294
2300
  # corresponding argument. So, it is safe to return an address
2295
2301
  # of the argument.
2296
2302
  return if rhs_pointee.type.parameter? && rhs_pointee.type.array?
@@ -11462,11 +11468,14 @@ module CBuiltin #:nodoc:
11462
11468
  class W0582 < PassiveCodeCheck
11463
11469
  def_registrant_phase C::Prepare2Phase
11464
11470
 
11471
+ include C::Conversion
11472
+
11465
11473
  def initialize(context)
11466
11474
  super
11467
11475
  interp = context[:c_interpreter]
11468
11476
  interp.on_function_call_expr_evaled += method(:call_function)
11469
11477
  interp.on_function_declared += method(:check)
11478
+ @enum_tbl = interp.environment.enumerator_table
11470
11479
  @function_calls = Hash.new { |hash, key| hash[key] = [] }
11471
11480
  end
11472
11481
 
@@ -11477,23 +11486,26 @@ module CBuiltin #:nodoc:
11477
11486
 
11478
11487
  param_types = function.type.parameter_types.reject { |type| type.void? }
11479
11488
 
11480
- @function_calls[function.name].each do |expr, arg_types|
11481
- if arg_types.size == param_types.size
11482
- conformed = arg_types.zip(param_types).all? { |atype, ptype|
11489
+ @function_calls[function.name].each do |funcall_expr, args|
11490
+ if args.size == param_types.size
11491
+ types = args.map { |ary| ary.first }.zip(param_types)
11492
+ conformed = types.each_with_index.all? { |(atype, ptype), index|
11493
+ funcall_expr.argument_expressions[index].constant?(@enum_tbl) &&
11494
+ untyped_pointer_conversion?(atype, ptype, args[index].last) or
11483
11495
  atype.convertible?(ptype)
11484
11496
  }
11485
11497
  else
11486
11498
  conformed = false
11487
11499
  end
11488
11500
 
11489
- W(:W0582, expr.location) unless conformed
11501
+ W(:W0582, funcall_expr.location) unless conformed
11490
11502
  end
11491
11503
  end
11492
11504
 
11493
- def call_function(expression, function, arg_variables, result_variable)
11505
+ def call_function(funcall_expr, function, arg_vars, result_var)
11494
11506
  if function.named?
11495
- arg_types = arg_variables.map { |var| var.type }
11496
- @function_calls[function.name].push([expression, arg_types])
11507
+ args = arg_vars.map { |var| [var.type, var.value.to_single_value] }
11508
+ @function_calls[function.name].push([funcall_expr, args])
11497
11509
  end
11498
11510
  end
11499
11511
  end
@@ -11501,11 +11513,14 @@ module CBuiltin #:nodoc:
11501
11513
  class W0583 < PassiveCodeCheck
11502
11514
  def_registrant_phase C::Prepare2Phase
11503
11515
 
11516
+ include C::Conversion
11517
+
11504
11518
  def initialize(context)
11505
11519
  super
11506
11520
  interp = context[:c_interpreter]
11507
11521
  interp.on_function_call_expr_evaled += method(:call_function)
11508
11522
  interp.on_function_defined += method(:check)
11523
+ @enum_tbl = interp.environment.enumerator_table
11509
11524
  @function_calls = Hash.new { |hash, key| hash[key] = [] }
11510
11525
  end
11511
11526
 
@@ -11516,23 +11531,26 @@ module CBuiltin #:nodoc:
11516
11531
 
11517
11532
  param_types = function.type.parameter_types.reject { |type| type.void? }
11518
11533
 
11519
- @function_calls[function.name].each do |expr, arg_types|
11520
- if arg_types.size == param_types.size
11521
- conformed = arg_types.zip(param_types).all? { |atype, ptype|
11534
+ @function_calls[function.name].each do |funcall_expr, args|
11535
+ if args.size == param_types.size
11536
+ types = args.map { |ary| ary.first }.zip(param_types)
11537
+ conformed = types.each_with_index.all? { |(atype, ptype), index|
11538
+ funcall_expr.argument_expressions[index].constant?(@enum_tbl) &&
11539
+ untyped_pointer_conversion?(atype, ptype, args[index].last) or
11522
11540
  atype.convertible?(ptype)
11523
11541
  }
11524
11542
  else
11525
11543
  conformed = false
11526
11544
  end
11527
11545
 
11528
- W(:W0583, expr.location) unless conformed
11546
+ W(:W0583, funcall_expr.location) unless conformed
11529
11547
  end
11530
11548
  end
11531
11549
 
11532
- def call_function(expression, function, arg_variables, result_variable)
11550
+ def call_function(funcall_expr, function, arg_vars, result_var)
11533
11551
  if function.named?
11534
- arg_types = arg_variables.map { |var| var.type }
11535
- @function_calls[function.name].push([expression, arg_types])
11552
+ args = arg_vars.map { |var| [var.type, var.value.to_single_value] }
11553
+ @function_calls[function.name].push([funcall_expr, args])
11536
11554
  end
11537
11555
  end
11538
11556
  end
@@ -11540,27 +11558,34 @@ module CBuiltin #:nodoc:
11540
11558
  class W0584 < PassiveCodeCheck
11541
11559
  def_registrant_phase C::Prepare2Phase
11542
11560
 
11561
+ include C::Conversion
11562
+
11543
11563
  def initialize(context)
11544
11564
  super
11545
11565
  interp = context[:c_interpreter]
11546
11566
  interp.on_function_call_expr_evaled += method(:check)
11567
+ @enum_tbl = interp.environment.enumerator_table
11547
11568
  end
11548
11569
 
11549
11570
  private
11550
- def check(expression, function, arg_variables, result_variable)
11571
+ def check(funcall_expr, function, arg_vars, result_var)
11551
11572
  return unless function.named?
11552
11573
  return unless kandr_style_definition_of(function)
11553
11574
  return if function.type.have_va_list?
11554
11575
 
11555
- arg_types = arg_variables.map { |var| var.type }
11576
+ args = arg_vars.map { |var| [var.type, var.value.to_single_value] }
11556
11577
  param_types = function.type.parameter_types.reject { |type| type.void? }
11557
11578
 
11558
- if arg_types.size == param_types.size
11559
- arg_types.zip(param_types).each_with_index do |(atype, ptype), index|
11560
- unless atype.convertible?(ptype)
11561
- W(:W0584,
11562
- expression.argument_expressions[index].location, index + 1)
11563
- end
11579
+ return unless args.size == param_types.size
11580
+
11581
+ args.zip(param_types).each_with_index do |(arg, ptype), index|
11582
+ arg_expr = funcall_expr.argument_expressions[index]
11583
+ if arg_expr.constant?(@enum_tbl)
11584
+ next if untyped_pointer_conversion?(arg.first, ptype, arg.last)
11585
+ end
11586
+
11587
+ unless arg.first.convertible?(ptype)
11588
+ W(:W0584, arg_expr.location, index + 1)
11564
11589
  end
11565
11590
  end
11566
11591
  end
@@ -11928,6 +11953,8 @@ module CBuiltin #:nodoc:
11928
11953
  class W0609 < PassiveCodeCheck
11929
11954
  def_registrant_phase C::Prepare2Phase
11930
11955
 
11956
+ include C::SyntaxNodeCollector
11957
+
11931
11958
  def initialize(context)
11932
11959
  super
11933
11960
  interp = context[:c_interpreter]
@@ -11935,12 +11962,46 @@ module CBuiltin #:nodoc:
11935
11962
  interp.on_equality_expr_evaled += method(:check)
11936
11963
  interp.on_logical_and_expr_evaled += method(:check)
11937
11964
  interp.on_logical_or_expr_evaled += method(:check)
11965
+ interp.on_for_stmt_started += method(:enter_for_statement)
11966
+ interp.on_c99_for_stmt_started += method(:enter_for_statement)
11967
+ interp.on_for_stmt_ended += method(:leave_for_statement)
11968
+ interp.on_c99_for_stmt_ended += method(:leave_for_statement)
11969
+ interp.on_for_ctrlexpr_evaled += method(:memorize_for_ctrlexpr)
11970
+ interp.on_c99_for_ctrlexpr_evaled += method(:memorize_for_ctrlexpr)
11971
+ @for_ctrlexpr_stack = []
11938
11972
  end
11939
11973
 
11940
11974
  private
11941
11975
  def check(binary_expression, lhs_variable, rhs_variable, result_variable)
11942
11976
  if result_variable.value.must_be_true?
11943
- W(:W0609, binary_expression.location)
11977
+ unless should_not_check?(binary_expression)
11978
+ W(:W0609, binary_expression.location)
11979
+ end
11980
+ end
11981
+ end
11982
+
11983
+ def enter_for_statement(for_statement)
11984
+ @for_ctrlexpr_stack.push(nil)
11985
+ end
11986
+
11987
+ def leave_for_statement(*)
11988
+ @for_ctrlexpr_stack.pop
11989
+ end
11990
+
11991
+ def memorize_for_ctrlexpr(for_statement, *)
11992
+ if explicit_ctrlexpr = for_statement.condition_statement.expression
11993
+ @for_ctrlexpr_stack[-1] = explicit_ctrlexpr
11994
+ end
11995
+ end
11996
+
11997
+ def should_not_check?(expr)
11998
+ if ctrlexpr = @for_ctrlexpr_stack.last
11999
+ collect_relational_expressions(ctrlexpr).include?(expr) ||
12000
+ collect_equality_expressions(ctrlexpr).include?(expr) ||
12001
+ collect_logical_and_expressions(ctrlexpr).include?(expr) ||
12002
+ collect_logical_or_expressions(ctrlexpr).include?(expr)
12003
+ else
12004
+ false
11944
12005
  end
11945
12006
  end
11946
12007
  end
@@ -11948,6 +12009,8 @@ module CBuiltin #:nodoc:
11948
12009
  class W0610 < PassiveCodeCheck
11949
12010
  def_registrant_phase C::Prepare2Phase
11950
12011
 
12012
+ include C::SyntaxNodeCollector
12013
+
11951
12014
  def initialize(context)
11952
12015
  super
11953
12016
  interp = context[:c_interpreter]
@@ -11955,12 +12018,46 @@ module CBuiltin #:nodoc:
11955
12018
  interp.on_equality_expr_evaled += method(:check)
11956
12019
  interp.on_logical_and_expr_evaled += method(:check)
11957
12020
  interp.on_logical_or_expr_evaled += method(:check)
12021
+ interp.on_for_stmt_started += method(:enter_for_statement)
12022
+ interp.on_c99_for_stmt_started += method(:enter_for_statement)
12023
+ interp.on_for_stmt_ended += method(:leave_for_statement)
12024
+ interp.on_c99_for_stmt_ended += method(:leave_for_statement)
12025
+ interp.on_for_ctrlexpr_evaled += method(:memorize_for_ctrlexpr)
12026
+ interp.on_c99_for_ctrlexpr_evaled += method(:memorize_for_ctrlexpr)
12027
+ @for_ctrlexpr_stack = []
11958
12028
  end
11959
12029
 
11960
12030
  private
11961
12031
  def check(binary_expression, lhs_variable, rhs_variable, result_variable)
11962
12032
  if result_variable.value.must_be_false?
11963
- W(:W0610, binary_expression.location)
12033
+ unless should_not_check?(binary_expression)
12034
+ W(:W0610, binary_expression.location)
12035
+ end
12036
+ end
12037
+ end
12038
+
12039
+ def enter_for_statement(for_statement)
12040
+ @for_ctrlexpr_stack.push(nil)
12041
+ end
12042
+
12043
+ def leave_for_statement(*)
12044
+ @for_ctrlexpr_stack.pop
12045
+ end
12046
+
12047
+ def memorize_for_ctrlexpr(for_statement, *)
12048
+ if explicit_ctrlexpr = for_statement.condition_statement.expression
12049
+ @for_ctrlexpr_stack[-1] = explicit_ctrlexpr
12050
+ end
12051
+ end
12052
+
12053
+ def should_not_check?(expr)
12054
+ if ctrlexpr = @for_ctrlexpr_stack.last
12055
+ collect_relational_expressions(ctrlexpr).include?(expr) ||
12056
+ collect_equality_expressions(ctrlexpr).include?(expr) ||
12057
+ collect_logical_and_expressions(ctrlexpr).include?(expr) ||
12058
+ collect_logical_or_expressions(ctrlexpr).include?(expr)
12059
+ else
12060
+ false
11964
12061
  end
11965
12062
  end
11966
12063
  end
@@ -14520,7 +14617,7 @@ module CBuiltin #:nodoc:
14520
14617
  when "+"
14521
14618
  unbound_value = lhs_variable.value + rhs_variable.value
14522
14619
  when "-"
14523
- unbound_value = lhs_variable.value + rhs_variable.value
14620
+ unbound_value = lhs_variable.value - rhs_variable.value
14524
14621
  when "*"
14525
14622
  unbound_value = lhs_variable.value * rhs_variable.value
14526
14623
  else
@@ -18051,25 +18148,44 @@ module CBuiltin #:nodoc:
18051
18148
  class W9003 < PassiveCodeCheck
18052
18149
  def_registrant_phase C::Prepare2Phase
18053
18150
 
18151
+ include C::Conversion
18152
+
18054
18153
  def initialize(context)
18055
18154
  super
18056
18155
  interp = context[:c_interpreter]
18057
18156
  interp.on_implicit_conv_performed += method(:check)
18157
+ @enum_tbl = interp.environment.enumerator_table
18058
18158
  end
18059
18159
 
18060
18160
  private
18061
- def check(initializer_or_expression, original_variable, result_variable)
18062
- from_type = original_variable.type
18063
- to_type = result_variable.type
18161
+ def check(init_or_expr, orig_var, result_var)
18162
+ from_type = orig_var.type
18163
+ to_type = result_var.type
18064
18164
 
18065
18165
  if from_type.undeclared? || from_type.unresolved? ||
18066
18166
  to_type.undeclared? || to_type.unresolved?
18067
18167
  return
18068
18168
  end
18069
18169
 
18170
+ case init_or_expr
18171
+ when C::Initializer
18172
+ if expr = init_or_expr.expression and expr.constant?(@enum_tbl)
18173
+ if untyped_pointer_conversion?(from_type, to_type, orig_var.value)
18174
+ return
18175
+ end
18176
+ end
18177
+ when C::Expression
18178
+ if init_or_expr.constant?(@enum_tbl)
18179
+ if untyped_pointer_conversion?(from_type, to_type, orig_var.value)
18180
+ return
18181
+ end
18182
+ end
18183
+ end
18184
+
18070
18185
  unless from_type.standard? && to_type.standard?
18071
18186
  unless from_type.convertible?(to_type)
18072
- W(:W9003, initializer_or_expression.location, from_type.brief_image)
18187
+ W(:W9003, init_or_expr.location,
18188
+ from_type.brief_image, to_type.brief_image)
18073
18189
  end
18074
18190
  end
18075
18191
  end
@@ -32,9 +32,9 @@
32
32
  module AdLint #:nodoc:
33
33
 
34
34
  MAJOR_VERSION = 2
35
- MINOR_VERSION = 4
36
- PATCH_VERSION = 10
37
- RELEASE_DATE = "2012-10-15"
35
+ MINOR_VERSION = 6
36
+ PATCH_VERSION = 0
37
+ RELEASE_DATE = "2012-10-22"
38
38
 
39
39
  TRAITS_SCHEMA_VERSION = "2.4.0"
40
40