adlint 1.14.0 → 1.16.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.
Files changed (70) hide show
  1. data/ChangeLog +265 -0
  2. data/MANIFEST +15 -0
  3. data/NEWS +30 -4
  4. data/etc/conf.d/noarch/adlint_all_bat.erb +1 -1
  5. data/etc/mesg.d/en_US/messages.yml +3 -3
  6. data/etc/mesg.d/ja_JP/messages.yml +3 -3
  7. data/features/message_detection/W0001.feature +2 -0
  8. data/features/message_detection/W0007.feature +8 -0
  9. data/features/message_detection/W0010.feature +4 -1
  10. data/features/message_detection/W0013.feature +8 -0
  11. data/features/message_detection/W0093.feature +3 -0
  12. data/features/message_detection/W0104.feature +7 -0
  13. data/features/message_detection/W0643.feature +80 -0
  14. data/features/message_detection/W0646.feature +115 -0
  15. data/features/message_detection/W0691.feature +100 -0
  16. data/features/message_detection/W0692.feature +32 -0
  17. data/features/message_detection/W0694.feature +128 -0
  18. data/features/message_detection/W0716.feature +3 -0
  19. data/features/message_detection/W0717.feature +3 -0
  20. data/features/message_detection/W0718.feature +3 -0
  21. data/features/message_detection/W0723.feature +2 -0
  22. data/features/message_detection/W0732.feature +3 -0
  23. data/features/message_detection/W0733.feature +3 -0
  24. data/features/message_detection/W0734.feature +8 -0
  25. data/features/message_detection/W0735.feature +8 -0
  26. data/features/message_detection/W0805.feature +92 -0
  27. data/features/message_detection/W0811.feature +79 -0
  28. data/features/message_detection/W1031.feature +7 -0
  29. data/features/message_detection/W1040.feature +89 -0
  30. data/features/message_detection/W1041.feature +15 -0
  31. data/features/message_detection/W1046.feature +60 -0
  32. data/features/message_detection/W1052.feature +3 -0
  33. data/features/message_detection/W1066.feature +3 -0
  34. data/features/message_detection/W1067.feature +3 -0
  35. data/features/message_detection/W1068.feature +3 -0
  36. data/features/message_detection/W1069.feature +5 -0
  37. data/features/message_detection/W1070.feature +6 -0
  38. data/features/message_detection/W1072.feature +1 -0
  39. data/features/message_detection/W1073.feature +145 -0
  40. data/features/message_detection/W1074.feature +139 -0
  41. data/features/message_detection/W1075.feature +86 -0
  42. data/features/message_detection/W1076.feature +66 -0
  43. data/features/message_detection/W1077.feature +105 -0
  44. data/features/message_detection/W9003.feature +4 -0
  45. data/lib/adlint/c/ctrlexpr.rb +3 -0
  46. data/lib/adlint/c/interp.rb +11 -5
  47. data/lib/adlint/c/lexer.rb +14 -3
  48. data/lib/adlint/c/message.rb +192 -0
  49. data/lib/adlint/c/parser.rb +19 -3
  50. data/lib/adlint/c/parser.y +18 -2
  51. data/lib/adlint/c/phase.rb +19 -6
  52. data/lib/adlint/c/syntax.rb +6 -0
  53. data/lib/adlint/c/type.rb +5 -1
  54. data/lib/adlint/cpp/constexpr.rb +3 -3
  55. data/lib/adlint/cpp/constexpr.y +3 -3
  56. data/lib/adlint/cpp/eval.rb +60 -86
  57. data/lib/adlint/cpp/lexer.rb +82 -28
  58. data/lib/adlint/cpp/macro.rb +64 -35
  59. data/lib/adlint/cpp/message.rb +137 -4
  60. data/lib/adlint/cpp/phase.rb +8 -0
  61. data/lib/adlint/cpp/syntax.rb +25 -0
  62. data/lib/adlint/lang.rb +2 -1
  63. data/lib/adlint/version.rb +2 -2
  64. data/share/doc/developers_guide_ja.html +3 -3
  65. data/share/doc/developers_guide_ja.texi +1 -1
  66. data/share/doc/users_guide_en.html +102 -85
  67. data/share/doc/users_guide_en.texi +85 -69
  68. data/share/doc/users_guide_ja.html +102 -94
  69. data/share/doc/users_guide_ja.texi +85 -77
  70. metadata +17 -2
@@ -0,0 +1,105 @@
1
+ Feature: W1077
2
+
3
+ W1077 detects that an array variable declared without number of its elements.
4
+
5
+ Scenario: 1-dimensional array variable declaration without size
6
+ Given a target source named "W1077.c" with:
7
+ """
8
+ extern int a[]; /* W1077 */
9
+ """
10
+ When I successfully run `adlint W1077.c` on noarch
11
+ Then the output should exactly match with:
12
+ | mesg | line | column |
13
+ | W0118 | 1 | 12 |
14
+ | W1077 | 1 | 12 |
15
+
16
+ Scenario: 1-dimensional array variable declaration with size
17
+ Given a target source named "W1077.c" with:
18
+ """
19
+ extern int a[3]; /* OK */
20
+ """
21
+ When I successfully run `adlint W1077.c` on noarch
22
+ Then the output should exactly match with:
23
+ | mesg | line | column |
24
+ | W0118 | 1 | 12 |
25
+
26
+ Scenario: 2-dimensional array variable declaration without all sizes
27
+ Given a target source named "W1077.c" with:
28
+ """
29
+ extern int a[][]; /* W1077 */
30
+ """
31
+ When I successfully run `adlint W1077.c` on noarch
32
+ Then the output should exactly match with:
33
+ | mesg | line | column |
34
+ | W0118 | 1 | 12 |
35
+ | W1028 | 1 | 12 |
36
+ | W1077 | 1 | 12 |
37
+
38
+ Scenario: 2-dimensional array variable declaration without outer size
39
+ Given a target source named "W1077.c" with:
40
+ """
41
+ extern int a[][3]; /* W1077 */
42
+ """
43
+ When I successfully run `adlint W1077.c` on noarch
44
+ Then the output should exactly match with:
45
+ | mesg | line | column |
46
+ | W0118 | 1 | 12 |
47
+ | W1077 | 1 | 12 |
48
+
49
+ Scenario: 2-dimensional array variable declaration with all sizes
50
+ Given a target source named "W1077.c" with:
51
+ """
52
+ extern int a[2][3]; /* OK */
53
+ """
54
+ When I successfully run `adlint W1077.c` on noarch
55
+ Then the output should exactly match with:
56
+ | mesg | line | column |
57
+ | W0118 | 1 | 12 |
58
+
59
+ Scenario: 3-dimensional array variable declaration without all sizes
60
+ Given a target source named "W1077.c" with:
61
+ """
62
+ extern int a[][][]; /* W1077 */
63
+ """
64
+ When I successfully run `adlint W1077.c` on noarch
65
+ Then the output should exactly match with:
66
+ | mesg | line | column |
67
+ | W0118 | 1 | 12 |
68
+ | W1028 | 1 | 12 |
69
+ | W1077 | 1 | 12 |
70
+
71
+ Scenario: 3-dimensional array variable declaration with all sizes
72
+ Given a target source named "W1077.c" with:
73
+ """
74
+ extern int a[1][2][3]; /* OK */
75
+ """
76
+ When I successfully run `adlint W1077.c` on noarch
77
+ Then the output should exactly match with:
78
+ | mesg | line | column |
79
+ | W0118 | 1 | 12 |
80
+
81
+ Scenario: cv-qualified 3-dimensional array variable declaration without all
82
+ sizes
83
+ Given a target source named "W1077.c" with:
84
+ """
85
+ extern const int a[][][]; /* W1077 */
86
+ """
87
+ When I successfully run `adlint W1077.c` on noarch
88
+ Then the output should exactly match with:
89
+ | mesg | line | column |
90
+ | W0118 | 1 | 18 |
91
+ | W1028 | 1 | 18 |
92
+ | W1077 | 1 | 18 |
93
+
94
+ Scenario: cv-qualified 3-dimensional array variable declaration with all
95
+ sizes
96
+ Given a target source named "W1077.c" with:
97
+ """
98
+ extern const int a[1][2][3]; /* OK */
99
+ """
100
+ When I successfully run `adlint W1077.c` on noarch
101
+ Then the output should exactly match with:
102
+ | mesg | line | column |
103
+ | W0118 | 1 | 18 |
104
+
105
+ # vim:ts=2:sw=2:sts=2:et:
@@ -22,6 +22,7 @@ Feature: W9003
22
22
  And the output should exactly match with:
23
23
  | mesg | line | column |
24
24
  | W0118 | 4 | 13 |
25
+ | W1076 | 6 | 13 |
25
26
  | W9003 | 8 | 9 |
26
27
  | W0728 | 8 | 9 |
27
28
  | W0629 | 6 | 13 |
@@ -44,6 +45,7 @@ Feature: W9003
44
45
  And the output should exactly match with:
45
46
  | mesg | line | column |
46
47
  | W0118 | 3 | 13 |
48
+ | W1076 | 5 | 13 |
47
49
  | W9003 | 7 | 9 |
48
50
  | W1059 | 7 | 9 |
49
51
  | W0629 | 5 | 13 |
@@ -66,6 +68,7 @@ Feature: W9003
66
68
  And the output should exactly match with:
67
69
  | mesg | line | column |
68
70
  | W0118 | 3 | 13 |
71
+ | W1076 | 5 | 13 |
69
72
  | W9003 | 7 | 9 |
70
73
  | W1053 | 7 | 9 |
71
74
  | W0629 | 5 | 13 |
@@ -116,6 +119,7 @@ Feature: W9003
116
119
  Then the output should match with /6:.*:W9003/
117
120
  And the output should exactly match with:
118
121
  | mesg | line | column |
122
+ | W1076 | 3 | 12 |
119
123
  | W0727 | 6 | 20 |
120
124
  | W9003 | 6 | 20 |
121
125
  | W9003 | 6 | 18 |
@@ -787,6 +787,9 @@ module C #:nodoc:
787
787
  __NOTREACHED__
788
788
  end
789
789
 
790
+ notify_variable_value_referred(@node, lhs_var)
791
+ notify_variable_value_referred(@node, rhs_var)
792
+
790
793
  case @operator
791
794
  when Operator::EQ, Operator::NE
792
795
  notify_equality_expr_evaled(@node, lhs_conv, rhs_conv, result)
@@ -162,15 +162,15 @@ module C #:nodoc:
162
162
  # a constant temporary variable.
163
163
  def_plugin_and_notifier :constant_referred, :constant_specifier, :variable
164
164
 
165
- # NOTE: Notified when the interpreter refer to a value of a variable while
165
+ # NOTE: Notified when the interpreter refers to a value of a variable while
166
166
  # evaluating an expression.
167
167
  def_plugin_and_notifier :variable_value_referred, :expression, :variable
168
168
 
169
- # NOTE: Notified when the interpreter overwrite a value of a variable while
170
- # evaluating an expression.
169
+ # NOTE: Notified when the interpreter overwrites a value of a variable
170
+ # while evaluating an expression.
171
171
  def_plugin_and_notifier :variable_value_updated, :expression, :variable
172
172
 
173
- # NOTE: Notified when the interpreter refer to a function object while
173
+ # NOTE: Notified when the interpreter refers to a function object while
174
174
  # evaluating an expression.
175
175
  def_plugin_and_notifier :function_referred, :expression, :function
176
176
 
@@ -421,7 +421,7 @@ module C #:nodoc:
421
421
  # NOTE: Notified when the interpreter ends execution of a translation-unit.
422
422
  def_plugin_and_notifier :translation_unit_ended, :translation_unit
423
423
 
424
- # NOTE: Notified when control reaches to a sequence-point.
424
+ # NOTE: Notified when the control reaches to a sequence-point.
425
425
  def_plugin_and_notifier :sequence_point_reached, :sequence_point
426
426
 
427
427
  def execute(node, *options)
@@ -1582,6 +1582,12 @@ module C #:nodoc:
1582
1582
  when then_var && else_var
1583
1583
  result_val = then_var.value.single_value_unified_with(else_var.value)
1584
1584
  result = temporary_variable(then_var.type, result_val)
1585
+ # FIXME: Not to over-warn about discarding a function return value.
1586
+ # Because the unified result is a new temporary variable, it is
1587
+ # impossible to relate a reference of the unified result and a
1588
+ # reference of the 2nd or 3rd expression's value.
1589
+ notify_variable_value_referred(node, then_var)
1590
+ notify_variable_value_referred(node, else_var)
1585
1591
  when then_var
1586
1592
  result = then_var
1587
1593
  when else_var
@@ -30,6 +30,7 @@
30
30
  #++
31
31
 
32
32
  require "adlint/lexer"
33
+ require "adlint/util"
33
34
  require "adlint/c/scanner"
34
35
  require "adlint/c/scope"
35
36
 
@@ -50,6 +51,10 @@ module C #:nodoc:
50
51
 
51
52
  attr_reader :translation_unit_fpath
52
53
 
54
+ extend Pluggable
55
+
56
+ def_plugin :on_string_literals_concatenated
57
+
53
58
  def add_typedef_name(token)
54
59
  @typedef_names.add(token.value)
55
60
  end
@@ -140,9 +145,11 @@ module C #:nodoc:
140
145
  until context.content.empty?
141
146
  next_token = tokenize(context)
142
147
  if next_token.type == :STRING_LITERAL
143
- return token.class.new(token.type, token.value.sub(/"\z/, "") +
144
- next_token.value.sub(/\AL?"/, ""),
145
- token.location)
148
+ result = token.class.new(token.type, token.value.sub(/"\z/, "") +
149
+ next_token.value.sub(/\AL?"/, ""),
150
+ token.location)
151
+ notify_string_literals_concatenated(token, next_token, result)
152
+ return result
146
153
  else
147
154
  @next_token = next_token
148
155
  break
@@ -210,6 +217,10 @@ module C #:nodoc:
210
217
  nil
211
218
  end
212
219
  end
220
+
221
+ def notify_string_literals_concatenated(former, latter, result)
222
+ on_string_literals_concatenated.invoke(former, latter, result)
223
+ end
213
224
  end
214
225
 
215
226
  class ScopedNameSet
@@ -11561,6 +11561,22 @@ module C #:nodoc:
11561
11561
  end
11562
11562
  end
11563
11563
 
11564
+ class W0646 < PassiveMessageDetection
11565
+ def initialize(context)
11566
+ super
11567
+ parser = context[:c_parser]
11568
+ parser.on_string_literals_concatenated += method(:check)
11569
+ end
11570
+
11571
+ private
11572
+ def check(former, latter, *)
11573
+ if former.value =~ /\A"/ && latter.value =~ /\AL"/i or
11574
+ former.value =~ /\AL"/i && latter.value =~ /\A"/
11575
+ W(:W0646, latter.location)
11576
+ end
11577
+ end
11578
+ end
11579
+
11564
11580
  class W0653 < PassiveMessageDetection
11565
11581
  def initialize(context)
11566
11582
  super
@@ -12102,6 +12118,21 @@ module C #:nodoc:
12102
12118
  end
12103
12119
  end
12104
12120
 
12121
+ class W0694 < PassiveMessageDetection
12122
+ def initialize(context)
12123
+ super
12124
+ interp = context[:c_interpreter]
12125
+ interp.on_function_call_expr_evaled += method(:check)
12126
+ end
12127
+
12128
+ private
12129
+ def check(function_call_expression, function, *)
12130
+ if function.named? && function.name == "assert"
12131
+ W(:W0694, function_call_expression.location)
12132
+ end
12133
+ end
12134
+ end
12135
+
12105
12136
  class W0703 < PassiveMessageDetection
12106
12137
  def initialize(context)
12107
12138
  super
@@ -14994,6 +15025,167 @@ module C #:nodoc:
14994
15025
  end
14995
15026
  end
14996
15027
 
15028
+ class W1073 < PassiveMessageDetection
15029
+ def initialize(context)
15030
+ super
15031
+ interp = context[:c_interpreter]
15032
+ interp.on_function_started += method(:enter_function)
15033
+ interp.on_function_ended += method(:leave_function)
15034
+ interp.on_function_call_expr_evaled += method(:add_return_value)
15035
+ interp.on_variable_value_referred += method(:refer_return_value)
15036
+ @current_function = nil
15037
+ end
15038
+
15039
+ private
15040
+ def enter_function(function_definition, *)
15041
+ @current_function = function_definition
15042
+ @return_values = {}
15043
+ end
15044
+
15045
+ def leave_function(*)
15046
+ if @current_function
15047
+ @return_values.each_value do |retval|
15048
+ unless retval[0]
15049
+ fun_name = retval[2].named? ? retval[2].name : "(anonymous)"
15050
+ W(:W1073, retval[1].location, fun_name)
15051
+ end
15052
+ end
15053
+ end
15054
+ @current_function = nil
15055
+ @return_values = nil
15056
+ end
15057
+
15058
+ def add_return_value(expr, function, arg_variables, result)
15059
+ if @current_function
15060
+ unless function.type.return_type.void?
15061
+ @return_values[result] = [false, expr, function]
15062
+ end
15063
+ end
15064
+ end
15065
+
15066
+ def refer_return_value(expr, variable)
15067
+ if @current_function
15068
+ if retval = @return_values[variable]
15069
+ retval[0] = true
15070
+ end
15071
+ end
15072
+ end
15073
+ end
15074
+
15075
+ class W1074 < PassiveMessageDetection
15076
+ def initialize(context)
15077
+ super
15078
+ visitor = context[:c_visitor]
15079
+ visitor.enter_sizeof_expression += method(:check)
15080
+ end
15081
+
15082
+ private
15083
+ def check(sizeof_expression)
15084
+ if sizeof_expression.operand.have_side_effect?
15085
+ W(:W1074, sizeof_expression.operand.location)
15086
+ end
15087
+ end
15088
+ end
15089
+
15090
+ class W1075 < PassiveMessageDetection
15091
+ def initialize(context)
15092
+ super
15093
+ interp = context[:c_interpreter]
15094
+ interp.on_variable_declared += method(:declare_variable)
15095
+ interp.on_variable_defined += method(:define_variable)
15096
+ interp.on_function_declared += method(:declare_function)
15097
+ interp.on_function_defined += method(:define_function)
15098
+ end
15099
+
15100
+ private
15101
+ def declare_variable(variable_declaration, variable)
15102
+ if variable.named?
15103
+ if variable.declared_as_static?
15104
+ sc_specifier = variable_declaration.storage_class_specifier
15105
+ unless sc_specifier && sc_specifier.type == :STATIC
15106
+ W(:W1075, variable_declaration.location, variable.name)
15107
+ end
15108
+ end
15109
+ end
15110
+ end
15111
+
15112
+ def define_variable(variable_definition, variable)
15113
+ if variable.named?
15114
+ if variable.declared_as_static?
15115
+ sc_specifier = variable_definition.storage_class_specifier
15116
+ unless sc_specifier && sc_specifier.type == :STATIC
15117
+ W(:W1075, variable_definition.location, variable.name)
15118
+ end
15119
+ end
15120
+ end
15121
+ end
15122
+
15123
+ def declare_function(function_declaration, function)
15124
+ if function.named?
15125
+ if function.declared_as_static?
15126
+ sc_specifier = function_declaration.storage_class_specifier
15127
+ unless sc_specifier && sc_specifier.type == :STATIC
15128
+ W(:W1075, function_declaration.location, function.name)
15129
+ end
15130
+ end
15131
+ end
15132
+ end
15133
+
15134
+ def define_function(function_definition, function)
15135
+ if function.named?
15136
+ if function.declared_as_static?
15137
+ sc_specifier = function_definition.storage_class_specifier
15138
+ unless sc_specifier && sc_specifier.type == :STATIC
15139
+ W(:W1075, function_definition.location, function.name)
15140
+ end
15141
+ end
15142
+ end
15143
+ end
15144
+ end
15145
+
15146
+ class W1076 < PassiveMessageDetection
15147
+ def initialize(context)
15148
+ super
15149
+ interp = context[:c_interpreter]
15150
+ interp.on_function_defined += method(:define_function)
15151
+ end
15152
+
15153
+ private
15154
+ def define_function(function_definition, function)
15155
+ if function.named? && function.declared_as_static?
15156
+ anterior_decls = function.declarations_and_definitions.reject { |decl|
15157
+ decl == function_definition
15158
+ }
15159
+ if anterior_decls.empty?
15160
+ W(:W1076, function_definition.location, function.name)
15161
+ end
15162
+ end
15163
+ end
15164
+ end
15165
+
15166
+ class W1077 < PassiveMessageDetection
15167
+ def initialize(context)
15168
+ super
15169
+ interp = context[:c_interpreter]
15170
+ interp.on_variable_declared += method(:check)
15171
+ end
15172
+
15173
+ private
15174
+ def check(variable_declaration, *)
15175
+ type = variable_declaration.type
15176
+ begin
15177
+ if type.array?
15178
+ unless type.length
15179
+ W(:W1077, variable_declaration.location)
15180
+ break
15181
+ end
15182
+ else
15183
+ break
15184
+ end
15185
+ end while type = type.base_type
15186
+ end
15187
+ end
15188
+
14997
15189
  class W9001 < PassiveMessageDetection
14998
15190
  def initialize(context)
14999
15191
  super
@@ -10,20 +10,22 @@ require 'racc/parser.rb'
10
10
  require "adlint/error"
11
11
  require "adlint/symbol"
12
12
  require "adlint/monitor"
13
+ require "adlint/util"
14
+ require "adlint/c/lexer"
13
15
  require "adlint/c/syntax"
14
16
 
15
17
  module AdLint
16
18
  module C
17
19
  class Parser < Racc::Parser
18
20
 
19
- module_eval(<<'...end parser.y/module_eval...', 'parser.y', 2028)
21
+ module_eval(<<'...end parser.y/module_eval...', 'parser.y', 2030)
20
22
 
21
23
  include MonitorUtil
22
24
  include ReportUtil
23
25
 
24
- def initialize(context, lexer)
26
+ def initialize(context)
25
27
  @context = context
26
- @lexer = lexer
28
+ @lexer = create_lexer(context[:c_source])
27
29
  @symbol_table = context[:symbol_table]
28
30
  @token_array = []
29
31
  @unnamed_tag_no = 0
@@ -35,7 +37,21 @@ def execute
35
37
  do_parse
36
38
  end
37
39
 
40
+ extend Pluggable
41
+
42
+ def_plugin :on_string_literals_concatenated
43
+
38
44
  private
45
+ def create_lexer(c_source)
46
+ Lexer.new(c_source).tap { |lexer| attach_lexer_plugin(lexer) }
47
+ end
48
+
49
+ def attach_lexer_plugin(lexer)
50
+ lexer.on_string_literals_concatenated += lambda { |*args|
51
+ on_string_literals_concatenated.invoke(*args)
52
+ }
53
+ end
54
+
39
55
  def next_token
40
56
  if token = @lexer.next_token
41
57
  @token_array.push(token)