adlint 3.0.8 → 3.0.10

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 (56) hide show
  1. data/ChangeLog +295 -0
  2. data/MANIFEST +9 -0
  3. data/NEWS +25 -4
  4. data/etc/mesg.d/c_builtin/en_US/messages.yml +1 -1
  5. data/etc/mesg.d/c_builtin/ja_JP/messages.yml +1 -1
  6. data/etc/mesg.d/core/en_US/messages.yml +1 -1
  7. data/etc/mesg.d/core/ja_JP/messages.yml +1 -1
  8. data/features/code_check/E0008.feature +20 -0
  9. data/features/code_check/W0093.feature +1 -1
  10. data/features/code_check/W0097.feature +30 -0
  11. data/features/code_check/W0100.feature +66 -0
  12. data/features/code_check/W0422.feature +157 -0
  13. data/features/code_check/W0459.feature +118 -0
  14. data/features/code_check/W0461.feature +115 -0
  15. data/features/code_check/W0610.feature +59 -0
  16. data/features/code_check/W0612.feature +29 -0
  17. data/features/code_check/W0613.feature +33 -0
  18. data/features/code_check/W0704.feature +25 -0
  19. data/features/code_check/W0705.feature +33 -0
  20. data/features/code_check/W1050.feature +43 -0
  21. data/features/code_check/W1071.feature +30 -0
  22. data/features/code_check/W9001.feature +24 -0
  23. data/lib/adlint/cc1/branch.rb +32 -9
  24. data/lib/adlint/cc1/builtin.rb +2 -2
  25. data/lib/adlint/cc1/conv.rb +33 -33
  26. data/lib/adlint/cc1/ctrlexpr.rb +30 -30
  27. data/lib/adlint/cc1/domain.rb +12 -4
  28. data/lib/adlint/cc1/environ.rb +2 -1
  29. data/lib/adlint/cc1/expr.rb +135 -125
  30. data/lib/adlint/cc1/format.rb +3 -3
  31. data/lib/adlint/cc1/interp.rb +123 -109
  32. data/lib/adlint/cc1/lexer.rb +44 -40
  33. data/lib/adlint/cc1/mediator.rb +2 -2
  34. data/lib/adlint/cc1/object.rb +121 -36
  35. data/lib/adlint/cc1/option.rb +1 -0
  36. data/lib/adlint/cc1/parser.rb +874 -845
  37. data/lib/adlint/cc1/parser.y +22 -2
  38. data/lib/adlint/cc1/syntax.rb +37 -18
  39. data/lib/adlint/cc1/type.rb +3 -3
  40. data/lib/adlint/cc1/value.rb +58 -50
  41. data/lib/adlint/cpp/lexer.rb +5 -1
  42. data/lib/adlint/cpp/macro.rb +30 -30
  43. data/lib/adlint/cpp/subst.rb +4 -4
  44. data/lib/adlint/exam/c_builtin/cc1_check.rb +172 -172
  45. data/lib/adlint/exam/c_builtin/cc1_check_shima.rb +11 -11
  46. data/lib/adlint/exam/c_builtin/cpp_check.rb +2 -2
  47. data/lib/adlint/memo.rb +13 -13
  48. data/lib/adlint/prelude.rb +2 -2
  49. data/lib/adlint/version.rb +2 -2
  50. data/share/doc/developers_guide_ja.html +7 -5
  51. data/share/doc/developers_guide_ja.texi +5 -3
  52. data/share/doc/users_guide_en.html +3 -3
  53. data/share/doc/users_guide_en.texi +1 -1
  54. data/share/doc/users_guide_ja.html +3 -3
  55. data/share/doc/users_guide_ja.texi +1 -1
  56. metadata +11 -2
@@ -34,3 +34,62 @@ Feature: W0610
34
34
  | W0593 | 1 | 21 |
35
35
  | W0589 | 2 | 6 |
36
36
  | W0593 | 2 | 6 |
37
+
38
+ Scenario: no explicit controlling-expression in for-statement
39
+ Given a target source named "fixture.c" with:
40
+ """
41
+ void foo(void)
42
+ {
43
+ int i;
44
+ for (i = 0; ; i++) {
45
+ if (i < 0) { /* W0610 */
46
+ i++;
47
+ }
48
+ if (i == 3) { /* OK not W0610 */
49
+ i++;
50
+ }
51
+ if (i == 5) { /* OK */
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ """
57
+ When I successfully run `adlint fixture.c` on noarch
58
+ Then the output should exactly match with:
59
+ | mesg | line | column |
60
+ | W0117 | 1 | 6 |
61
+ | W0610 | 5 | 15 |
62
+ | W0613 | 5 | 15 |
63
+ | W0708 | 9 | 14 |
64
+ | W9001 | 6 | 13 |
65
+ | W0114 | 4 | 5 |
66
+ | W0628 | 1 | 6 |
67
+
68
+ Scenario: no explicit controlling-expression in c99-for-statement
69
+ Given a target source named "fixture.c" with:
70
+ """
71
+ void foo(void)
72
+ {
73
+ for (int i = 0; ; i++) {
74
+ if (i < 0) { /* W0610 */
75
+ i++;
76
+ }
77
+ if (i == 3) { /* OK not W0610 */
78
+ i++;
79
+ }
80
+ if (i == 5) { /* OK */
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ """
86
+ When I successfully run `adlint fixture.c` on noarch
87
+ Then the output should exactly match with:
88
+ | mesg | line | column |
89
+ | W0117 | 1 | 6 |
90
+ | W0610 | 4 | 15 |
91
+ | W0613 | 4 | 15 |
92
+ | W0708 | 8 | 14 |
93
+ | W9001 | 5 | 13 |
94
+ | W0114 | 3 | 5 |
95
+ | W0628 | 1 | 6 |
@@ -0,0 +1,29 @@
1
+ Feature: W0612
2
+
3
+ W0612 detects that a controlling expression of the selection-statement always
4
+ be true.
5
+
6
+ Scenario: bitwise and expression as the controlling expression
7
+ Given a target source named "fixture.c" with:
8
+ """
9
+ void foo(unsigned int ui)
10
+ {
11
+ while (ui) {
12
+ if (ui & 1) { /* OK not W0612 */
13
+ break;
14
+ }
15
+ else {
16
+ ui >>= 1;
17
+ }
18
+ }
19
+ }
20
+ """
21
+ When I successfully run `adlint fixture.c` on noarch
22
+ Then the output should exactly match with:
23
+ | mesg | line | column |
24
+ | W0117 | 1 | 6 |
25
+ | W0167 | 4 | 18 |
26
+ | W0572 | 4 | 16 |
27
+ | W0114 | 3 | 5 |
28
+ | W0114 | 4 | 9 |
29
+ | W0628 | 1 | 6 |
@@ -0,0 +1,33 @@
1
+ Feature: W0613
2
+
3
+ W0613 detects that a controlling expression of the iteration-statement always
4
+ be false.
5
+
6
+ Scenario: array-subscript-expression refers to global constant table
7
+ Given a target source named "fixture.c" with:
8
+ """
9
+ static const int a[256] = { 0, 1, 0, 0, 1 };
10
+
11
+ extern unsigned char foo(int);
12
+
13
+ int main(void)
14
+ {
15
+ int i, j = 0;
16
+
17
+ for (i = 0; a[foo(i)]; i++) { /* OK */
18
+ j++;
19
+ }
20
+
21
+ return j;
22
+ }
23
+ """
24
+ When I successfully run `adlint fixture.c` on noarch
25
+ Then the output should exactly match with:
26
+ | mesg | line | column |
27
+ | W0118 | 3 | 22 |
28
+ | W0246 | 9 | 22 |
29
+ | W0736 | 1 | 18 |
30
+ | W0043 | 1 | 27 |
31
+ | W0950 | 1 | 20 |
32
+ | W0114 | 9 | 5 |
33
+ | W0425 | 7 | 12 |
@@ -0,0 +1,25 @@
1
+ Feature: W0704
2
+
3
+ W0704 detects that an ordinary identifier is hiding other identifier.
4
+
5
+ Scenario: hiding typedef name by enumerator name
6
+ Given a target source named "fixture.c" with:
7
+ """
8
+ typedef double DOUBLE;
9
+
10
+ void foo(void)
11
+ {
12
+ enum arg_type { INT, DOUBLE } type;
13
+ type = DOUBLE;
14
+ }
15
+ """
16
+ When I successfully run `adlint fixture.c` on noarch
17
+ Then the output should exactly match with:
18
+ | mesg | line | column |
19
+ | W0117 | 3 | 6 |
20
+ | W0704 | 5 | 26 |
21
+ | C0001 | 1 | 16 |
22
+ | W0789 | 5 | 26 |
23
+ | C0001 | 1 | 16 |
24
+ | W0100 | 5 | 35 |
25
+ | W0628 | 3 | 6 |
@@ -360,3 +360,36 @@ Feature: W0705
360
360
  | W0502 | 5 | 9 |
361
361
  | W0498 | 7 | 18 |
362
362
  | W0628 | 3 | 5 |
363
+
364
+ Scenario: size of array is specified by the global constant variable
365
+ Given a target source named "fixture.c" with:
366
+ """
367
+ const int size = 2;
368
+
369
+ void foo(void)
370
+ {
371
+ int i;
372
+ char a[size];
373
+ for (i = 0; i < size; i++) {
374
+ a[i] = (char) 0; /* OK */
375
+ }
376
+ }
377
+
378
+ void bar(void)
379
+ {
380
+ int i;
381
+ char a[size];
382
+ for (i = 0; i < size; i++) {
383
+ a[i] = (char) 0; /* OK */
384
+ }
385
+ }
386
+ """
387
+ When I successfully run `adlint fixture.c` on noarch
388
+ Then the output should exactly match with:
389
+ | mesg | line | column |
390
+ | W0117 | 1 | 11 |
391
+ | W0117 | 3 | 6 |
392
+ | W0117 | 12 | 6 |
393
+ | W0628 | 3 | 6 |
394
+ | W0628 | 12 | 6 |
395
+ | W0593 | 1 | 11 |
@@ -0,0 +1,43 @@
1
+ Feature: W1050
2
+
3
+ W1050 detects that an explicit conversion to signed integer must cause
4
+ overflow.
5
+
6
+ Scenario: conversion from `int' to `signed char'
7
+ Given a target source named "fixture.c" with:
8
+ """
9
+ static void foo(const int i)
10
+ {
11
+ if (i > 127) {
12
+ const signed char c = (signed char) i; /* W1050 */
13
+ }
14
+ if (i < -128) {
15
+ const signed char c = (signed char) i; /* W1050 */
16
+ }
17
+
18
+ if (i > 100) {
19
+ const signed char c = (signed char) i; /* OK but W1049 */
20
+ }
21
+ if (i < -100) {
22
+ const signed char c = (signed char) i; /* OK but W1049 */
23
+ }
24
+
25
+ if (i > -129 && i < 128) {
26
+ const signed char c = (signed char) i; /* OK */
27
+ }
28
+ }
29
+ """
30
+ When I successfully run `adlint fixture.c` on noarch
31
+ Then the output should exactly match with:
32
+ | mesg | line | column |
33
+ | W1076 | 1 | 13 |
34
+ | W1050 | 4 | 31 |
35
+ | W1050 | 7 | 31 |
36
+ | W1049 | 11 | 31 |
37
+ | W1049 | 14 | 31 |
38
+ | W0629 | 1 | 13 |
39
+ | W0489 | 17 | 9 |
40
+ | W0490 | 17 | 9 |
41
+ | W0499 | 17 | 9 |
42
+ | W0502 | 17 | 9 |
43
+ | W0628 | 1 | 13 |
@@ -79,3 +79,33 @@ Feature: W1071
79
79
  | W0104 | 1 | 13 |
80
80
  | W1071 | 1 | 5 |
81
81
  | W0628 | 1 | 5 |
82
+
83
+ Scenario: array-subscript-expression as the controlling expression
84
+ Given a target source named "fixture.c" with:
85
+ """
86
+ struct foo {
87
+ int len;
88
+ int ary[];
89
+ };
90
+
91
+ static void foo(struct foo *p)
92
+ {
93
+ int i;
94
+ for (i = 0; i < p->len; i++) {
95
+ if (p->ary[i]) return;
96
+ }
97
+ }
98
+ """
99
+ When I successfully run `adlint fixture.c` on noarch
100
+ Then the output should exactly match with:
101
+ | mesg | line | column |
102
+ | W1076 | 6 | 13 |
103
+ | W0422 | 9 | 22 |
104
+ | W0422 | 10 | 14 |
105
+ | W0104 | 6 | 29 |
106
+ | W0105 | 6 | 29 |
107
+ | W1071 | 6 | 13 |
108
+ | W0629 | 6 | 13 |
109
+ | W0414 | 10 | 24 |
110
+ | W0114 | 10 | 9 |
111
+ | W0628 | 6 | 13 |
@@ -29,3 +29,27 @@ Feature: W9001
29
29
  When I successfully run `adlint fixture.c` on noarch
30
30
  Then the output should exactly match with:
31
31
  | mesg | line | column |
32
+
33
+ Scenario: indefinitive controlling variable narrowing
34
+ Given a target source named "fixture.c" with:
35
+ """
36
+ void foo(int i)
37
+ {
38
+ if (i > 0) {
39
+ do {
40
+ puts("foo"); /* OK not W9001 */
41
+ } while (i == -1);
42
+ }
43
+ }
44
+ """
45
+ When I successfully run `adlint fixture.c` on noarch
46
+ Then the output should exactly match with:
47
+ | mesg | line | column |
48
+ | W0117 | 1 | 6 |
49
+ | W0109 | 5 | 13 |
50
+ | W0610 | 6 | 20 |
51
+ | W0614 | 6 | 20 |
52
+ | W0104 | 1 | 14 |
53
+ | W1073 | 5 | 17 |
54
+ | W0947 | 5 | 18 |
55
+ | W0628 | 1 | 6 |
@@ -38,8 +38,8 @@ module Cc1 #:nodoc:
38
38
  class Branch
39
39
  include BranchOptions
40
40
 
41
- def initialize(br_group, *opts)
42
- @group = br_group
41
+ def initialize(branch_group, *opts)
42
+ @group = branch_group
43
43
  @options = opts
44
44
  @break_event = nil
45
45
  @controlling_expression = nil
@@ -103,9 +103,17 @@ module Cc1 #:nodoc:
103
103
  # TODO: Study about introducing inter-value-constraints to correctly
104
104
  # manage value domains of controlling variables related with each
105
105
  # other.
106
- env.end_versioning(break_with_return?, true)
106
+ if @group.in_iteration? && !smother_break?
107
+ env.end_versioning(break_with_return? || break_with_break?, true)
108
+ else
109
+ env.end_versioning(break_with_return?, true)
110
+ end
107
111
  else
108
- env.end_versioning(break_with_return?, false)
112
+ if @group.in_iteration? && !smother_break?
113
+ env.end_versioning(break_with_return? || break_with_break?, false)
114
+ else
115
+ env.end_versioning(break_with_return?, false)
116
+ end
109
117
  end
110
118
 
111
119
  if final?
@@ -167,13 +175,15 @@ module Cc1 #:nodoc:
167
175
  include BranchOptions
168
176
  include BranchGroupOptions
169
177
 
170
- def initialize(env, *opts)
178
+ def initialize(env, parent, *opts)
171
179
  @environment = env
180
+ @parent_group = parent
172
181
  @options = opts
173
182
  @branches = []
174
183
  end
175
184
 
176
185
  attr_reader :environment
186
+ attr_reader :parent_group
177
187
  attr_reader :branches
178
188
 
179
189
  def add_options(*new_opts)
@@ -184,14 +194,27 @@ module Cc1 #:nodoc:
184
194
  @options.include?(COMPLETE)
185
195
  end
186
196
 
197
+ def iteration?
198
+ @options.include?(ITERATION)
199
+ end
200
+
201
+ def in_iteration?
202
+ branch_group = @parent_group
203
+ while branch_group
204
+ return true if branch_group.iteration?
205
+ branch_group = branch_group.parent_group
206
+ end
207
+ false
208
+ end
209
+
187
210
  def create_first_branch(*opts)
188
- @branches.push(new_br = Branch.new(self, FIRST, *opts))
189
- new_br
211
+ @branches.push(new_branch = Branch.new(self, FIRST, *opts))
212
+ new_branch
190
213
  end
191
214
 
192
215
  def create_trailing_branch(*opts)
193
- @branches.push(new_br = Branch.new(self, *opts))
194
- new_br
216
+ @branches.push(new_branch = Branch.new(self, *opts))
217
+ new_branch
195
218
  end
196
219
 
197
220
  def all_controlling_variables
@@ -73,8 +73,8 @@ module Cc1 #:nodoc:
73
73
 
74
74
  def call(interp, *, args)
75
75
  puts "__adlint__eval"
76
- char_ary = interp.pointee_of(args.first.first)
77
- if char_ary && char_ary.type.array?
76
+ char_ary = args.first.first
77
+ if char_ary.type.array?
78
78
  without_nil = char_ary.value.to_single_value.values[0..-2]
79
79
  prog_text = without_nil.map { |char| char.unique_sample.chr }.join
80
80
  if prog_text.empty?
@@ -35,55 +35,55 @@ module Cc1 #:nodoc:
35
35
  module Conversion
36
36
  # NOTE: Host class of this module must include InterpreterMediator.
37
37
 
38
- def do_conversion(org_var, to_type)
39
- if org_var.type.coercible?(to_type)
38
+ def do_conversion(orig_var, to_type)
39
+ if orig_var.type.coercible?(to_type)
40
40
  # NOTE: Value will be coerced into the destination type in
41
41
  # VariableTableMediator#create_tmpvar.
42
- create_tmpvar(to_type, wrap_around_value(org_var, to_type))
42
+ create_tmpvar(to_type, wrap_around_value(orig_var, to_type))
43
43
  else
44
44
  nil
45
45
  end
46
46
  end
47
47
 
48
- def do_integer_promotion(org_var)
49
- return org_var unless org_var.type.integer?
48
+ def do_integer_promotion(orig_var)
49
+ return orig_var unless orig_var.type.integer?
50
50
 
51
- promoted_type = org_var.type.integer_promoted_type
52
- if org_var.type.same_as?(promoted_type)
53
- org_var
51
+ promoted_type = orig_var.type.integer_promoted_type
52
+ if orig_var.type.same_as?(promoted_type)
53
+ orig_var
54
54
  else
55
- do_conversion(org_var, promoted_type) || org_var
55
+ do_conversion(orig_var, promoted_type) || orig_var
56
56
  end
57
57
  end
58
58
 
59
- def do_usual_arithmetic_conversion(lhs_org, rhs_org)
60
- if lhs_org.type.pointer? && rhs_org.type.pointer?
61
- return lhs_org, rhs_org
59
+ def do_usual_arithmetic_conversion(lhs_orig, rhs_orig)
60
+ if lhs_orig.type.pointer? && rhs_orig.type.pointer?
61
+ return lhs_orig, rhs_orig
62
62
  end
63
63
 
64
- arith_type = lhs_org.type.arithmetic_type_with(rhs_org.type)
64
+ arith_type = lhs_orig.type.arithmetic_type_with(rhs_orig.type)
65
65
 
66
- if lhs_org.type.same_as?(arith_type)
67
- lhs_conved = lhs_org
66
+ if lhs_orig.type.same_as?(arith_type)
67
+ lhs_conved = lhs_orig
68
68
  else
69
- lhs_conved = do_conversion(lhs_org, arith_type) || lhs_org
69
+ lhs_conved = do_conversion(lhs_orig, arith_type) || lhs_orig
70
70
  end
71
71
 
72
- if rhs_org.type.same_as?(arith_type)
73
- rhs_conved = rhs_org
72
+ if rhs_orig.type.same_as?(arith_type)
73
+ rhs_conved = rhs_orig
74
74
  else
75
- rhs_conved = do_conversion(rhs_org, arith_type) || rhs_org
75
+ rhs_conved = do_conversion(rhs_orig, arith_type) || rhs_orig
76
76
  end
77
77
 
78
78
  return lhs_conved, rhs_conved
79
79
  end
80
80
 
81
- def do_default_argument_promotion(org_var)
82
- promoted_type = org_var.type.argument_promoted_type
83
- if org_var.type.same_as?(promoted_type)
84
- org_var
81
+ def do_default_argument_promotion(orig_var)
82
+ promoted_type = orig_var.type.argument_promoted_type
83
+ if orig_var.type.same_as?(promoted_type)
84
+ orig_var
85
85
  else
86
- do_conversion(org_var, promoted_type) || org_var
86
+ do_conversion(orig_var, promoted_type) || orig_var
87
87
  end
88
88
  end
89
89
 
@@ -115,23 +115,23 @@ module Cc1 #:nodoc:
115
115
  end
116
116
 
117
117
  private
118
- def wrap_around_value(org_var, to_type)
119
- return org_var.value unless org_var.type.scalar? && to_type.scalar?
118
+ def wrap_around_value(orig_var, to_type)
119
+ return orig_var.value unless orig_var.type.scalar? && to_type.scalar?
120
120
 
121
121
  case
122
- when org_var.type.signed? && to_type.unsigned?
122
+ when orig_var.type.signed? && to_type.unsigned?
123
123
  min_val = scalar_value_of(to_type.min)
124
- if (org_var.value < min_val).may_be_true?
125
- return min_val - org_var.value + scalar_value_of(1)
124
+ if (orig_var.value < min_val).may_be_true?
125
+ return min_val - orig_var.value + scalar_value_of(1)
126
126
  end
127
- when org_var.type.unsigned? && to_type.signed?
127
+ when orig_var.type.unsigned? && to_type.signed?
128
128
  max_val = scalar_value_of(to_type.max)
129
- if (org_var.value > max_val).may_be_true?
130
- return max_val - org_var.value + scalar_value_of(1)
129
+ if (orig_var.value > max_val).may_be_true?
130
+ return max_val - orig_var.value + scalar_value_of(1)
131
131
  end
132
132
  end
133
133
 
134
- org_var.value
134
+ orig_var.value
135
135
  end
136
136
 
137
137
  def void_pointer?(type)