adlint 1.14.0 → 1.16.0

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