adlint 1.12.0 → 1.14.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.
@@ -0,0 +1,120 @@
1
+ Feature: W1069
2
+
3
+ W1069 detects that no trailing `else' clause is found in this `if-else-if'
4
+ statements chain.
5
+
6
+ Scenario: no trailing `else' in `if-else-if' statements chain
7
+ Given a target source named "W1069.c" with:
8
+ """
9
+ static int func(int i)
10
+ {
11
+ if (i == 2) { /* W1069 */
12
+ return 0;
13
+ }
14
+ else if (i == 4) {
15
+ return 1;
16
+ }
17
+ return 2;
18
+ }
19
+ """
20
+ When I successfully run `adlint W1069.c` on noarch
21
+ Then the output should exactly match with:
22
+ | mesg | line | column |
23
+ | W0104 | 1 | 21 |
24
+ | W0629 | 1 | 12 |
25
+ | W1069 | 3 | 5 |
26
+ | W0628 | 1 | 12 |
27
+
28
+ Scenario: no trailing `else' in `if-else-if-else-if' statements chain
29
+ Given a target source named "W1069.c" with:
30
+ """
31
+ static int func(int i)
32
+ {
33
+ if (i == 2) { /* W1069 */
34
+ return 0;
35
+ }
36
+ else if (i == 4) {
37
+ return 1;
38
+ }
39
+ else if (i == 6) {
40
+ return 2;
41
+ }
42
+ return 4;
43
+ }
44
+ """
45
+ When I successfully run `adlint W1069.c` on noarch
46
+ Then the output should exactly match with:
47
+ | mesg | line | column |
48
+ | W0104 | 1 | 21 |
49
+ | W0629 | 1 | 12 |
50
+ | W1069 | 3 | 5 |
51
+ | W0628 | 1 | 12 |
52
+
53
+ Scenario: `else' clause at the last of `if-else-if-else-if' statements chain
54
+ Given a target source named "W1069.c" with:
55
+ """
56
+ static int func(int i)
57
+ {
58
+ if (i == 2) { /* OK */
59
+ return 0;
60
+ }
61
+ else if (i == 4) {
62
+ return 1;
63
+ }
64
+ else if (i == 6) {
65
+ return 2;
66
+ }
67
+ else {
68
+ return 3;
69
+ }
70
+ }
71
+ """
72
+ When I successfully run `adlint W1069.c` on noarch
73
+ Then the output should exactly match with:
74
+ | mesg | line | column |
75
+ | W0104 | 1 | 21 |
76
+ | W0629 | 1 | 12 |
77
+ | W0628 | 1 | 12 |
78
+
79
+ Scenario: standalone `if' statement
80
+ Given a target source named "W1069.c" with:
81
+ """
82
+ static int func(int i)
83
+ {
84
+ if (i == 2) { /* OK */
85
+ return 0;
86
+ }
87
+ return 10;
88
+ }
89
+ """
90
+ When I successfully run `adlint W1069.c` on noarch
91
+ Then the output should exactly match with:
92
+ | mesg | line | column |
93
+ | W0104 | 1 | 21 |
94
+ | W0629 | 1 | 12 |
95
+ | W0628 | 1 | 12 |
96
+
97
+ Scenario: `else' clause at the last of `if-else-if' statements chain
98
+ Given a target source named "W1069.c" with:
99
+ """
100
+ static int func(int i)
101
+ {
102
+ if (i == 2) { /* OK */
103
+ return 0;
104
+ }
105
+ else if (i == 4) {
106
+ return 1;
107
+ }
108
+ else {
109
+ return 2;
110
+ }
111
+ }
112
+ """
113
+ When I successfully run `adlint W1069.c` on noarch
114
+ Then the output should exactly match with:
115
+ | mesg | line | column |
116
+ | W0104 | 1 | 21 |
117
+ | W0629 | 1 | 12 |
118
+ | W0628 | 1 | 12 |
119
+
120
+ # vim:ts=2:sw=2:sts=2:et:
@@ -0,0 +1,145 @@
1
+ Feature: W1070
2
+
3
+ W1070 detects that a `switch' statement can be translated into if-else
4
+ statement because there are only two execution paths.
5
+
6
+ Scenario: `switch' statement which has only two execution paths
7
+ Given a target source named "W1070.c" with:
8
+ """
9
+ static int func(const int i)
10
+ {
11
+ switch (i) { /* W1070 */
12
+ case 0:
13
+ return 4;
14
+ default:
15
+ return 8;
16
+ }
17
+ }
18
+ """
19
+ When I successfully run `adlint W1070.c` on noarch
20
+ Then the output should exactly match with:
21
+ | mesg | line | column |
22
+ | W0629 | 1 | 12 |
23
+ | W1070 | 3 | 5 |
24
+ | W0628 | 1 | 12 |
25
+
26
+ Scenario: `switch' statement which has only two execution paths and doesn't
27
+ have `default' clause
28
+ Given a target source named "W1070.c" with:
29
+ """
30
+ static int func(const int i)
31
+ {
32
+ switch (i) { /* W1070 */
33
+ case 0:
34
+ return 4;
35
+ case 1:
36
+ return 6;
37
+ }
38
+ return 10;
39
+ }
40
+ """
41
+ When I successfully run `adlint W1070.c` on noarch
42
+ Then the output should exactly match with:
43
+ | mesg | line | column |
44
+ | W0629 | 1 | 12 |
45
+ | W0003 | 3 | 5 |
46
+ | W1070 | 3 | 5 |
47
+ | W0628 | 1 | 12 |
48
+
49
+ Scenario: `switch' statement which has only two execution paths and the
50
+ control never reaches to one of that paths
51
+ Given a target source named "W1070.c" with:
52
+ """
53
+ static int func(const int i)
54
+ {
55
+ if (i > 5) {
56
+ switch (i) { /* W1070, W0781 */
57
+ case 5:
58
+ return 2;
59
+ default:
60
+ return 3;
61
+ }
62
+ }
63
+ return 10;
64
+ }
65
+ """
66
+ When I successfully run `adlint W1070.c` on noarch
67
+ Then the output should exactly match with:
68
+ | mesg | line | column |
69
+ | W0629 | 1 | 12 |
70
+ | W9001 | 5 | 9 |
71
+ | W9001 | 6 | 13 |
72
+ | W0781 | 4 | 9 |
73
+ | W1070 | 4 | 9 |
74
+ | W0628 | 1 | 12 |
75
+
76
+ Scenario: `switch' statement which has only one execution path
77
+ Given a target source named "W1070.c" with:
78
+ """
79
+ static int func(const int i)
80
+ {
81
+ switch (i) { /* W0781 */
82
+ default:
83
+ return 8;
84
+ }
85
+ }
86
+ """
87
+ When I successfully run `adlint W1070.c` on noarch
88
+ Then the output should exactly match with:
89
+ | mesg | line | column |
90
+ | W0629 | 1 | 12 |
91
+ | W0781 | 3 | 5 |
92
+ | W0628 | 1 | 12 |
93
+
94
+ Scenario: `switch' statement which has three execution paths, but the control
95
+ never reaches to only one of that paths
96
+ Given a target source named "W1070.c" with:
97
+ """
98
+ static int func(const int i)
99
+ {
100
+ if (i > 5) {
101
+ switch (i) { /* W0781 */
102
+ case 0:
103
+ return 1;
104
+ case 5:
105
+ return 2;
106
+ default:
107
+ return 3;
108
+ }
109
+ }
110
+ return 10;
111
+ }
112
+ """
113
+ When I successfully run `adlint W1070.c` on noarch
114
+ Then the output should exactly match with:
115
+ | mesg | line | column |
116
+ | W0629 | 1 | 12 |
117
+ | W9001 | 5 | 9 |
118
+ | W9001 | 6 | 13 |
119
+ | W9001 | 7 | 9 |
120
+ | W9001 | 8 | 13 |
121
+ | W0781 | 4 | 9 |
122
+ | W0628 | 1 | 12 |
123
+
124
+ Scenario: `switch' statement which has three execution paths
125
+ Given a target source named "W1070.c" with:
126
+ """
127
+ static int func(const int i)
128
+ {
129
+ switch (i) { /* OK */
130
+ case 0:
131
+ return 4;
132
+ case 1:
133
+ return 6;
134
+ default:
135
+ return 8;
136
+ }
137
+ }
138
+ """
139
+ When I successfully run `adlint W1070.c` on noarch
140
+ Then the output should exactly match with:
141
+ | mesg | line | column |
142
+ | W0629 | 1 | 12 |
143
+ | W0628 | 1 | 12 |
144
+
145
+ # vim:ts=2:sw=2:sts=2:et:
@@ -0,0 +1,32 @@
1
+ Feature: W1072
2
+
3
+ W1072 detects that a `goto' statement is found.
4
+
5
+ Scenario: `goto' statement is found
6
+ Given a target source named "W1072.c" with:
7
+ """
8
+ static int func(int i)
9
+ {
10
+ if (i == 1) {
11
+ goto Label1; /* W1072 */
12
+ }
13
+
14
+ goto Label2; /* W1072 */
15
+
16
+ Label1:
17
+ i = 10;
18
+ Label2:
19
+ i = 20;
20
+
21
+ return i;
22
+ }
23
+ """
24
+ When I successfully run `adlint W1072.c` on noarch
25
+ Then the output should exactly match with:
26
+ | mesg | line | column |
27
+ | W0629 | 1 | 12 |
28
+ | W1072 | 4 | 9 |
29
+ | W1072 | 7 | 5 |
30
+ | W0628 | 1 | 12 |
31
+
32
+ # vim:ts=2:sw=2:sts=2:et:
@@ -354,6 +354,9 @@ module C #:nodoc:
354
354
  def_plugin_and_notifier :return_stmt_evaled,
355
355
  :return_statement, :result_variable
356
356
 
357
+ # NOTE: Notified when the interpreter evaluates an implicit return.
358
+ def_plugin_and_notifier :implicit_return_evaled
359
+
357
360
  # NOTE: Notified when the interpreter evaluates a controlling expression of
358
361
  # the if-statement.
359
362
  def_plugin_and_notifier :if_ctrlexpr_evaled, :if_statement, :ctrlexpr_value
@@ -816,16 +819,7 @@ module C #:nodoc:
816
819
 
817
820
  reset_environment
818
821
  resolve_unresolved_type(node)
819
-
820
- if function = function_named(node.identifier.value)
821
- function.declarations_and_definitions.each do |decl_or_def|
822
- decl_or_def.mark_as_referred_by(node.identifier)
823
- end
824
- function.declarations_and_definitions.push(node)
825
- else
826
- function = define_explicit_function(node)
827
- end
828
-
822
+ function = lookup_or_define_function(node)
829
823
  notify_function_defined(node, function)
830
824
 
831
825
  begin
@@ -838,6 +832,7 @@ module C #:nodoc:
838
832
 
839
833
  BreakEvent.catch do
840
834
  node.function_body.block_items.each { |item| interpret(item) }
835
+ notify_implicit_return_evaled
841
836
  end
842
837
 
843
838
  notify_block_ended(node.function_body)
@@ -847,6 +842,18 @@ module C #:nodoc:
847
842
  interpreter._leave_function(node)
848
843
  end
849
844
  end
845
+
846
+ def lookup_or_define_function(function_definition)
847
+ if function = function_named(function_definition.identifier.value)
848
+ function.declarations_and_definitions.each do |decl_or_def|
849
+ decl_or_def.mark_as_referred_by(function_definition.identifier)
850
+ end
851
+ function.declarations_and_definitions.push(function_definition)
852
+ else
853
+ function = define_explicit_function(function_definition)
854
+ end
855
+ function
856
+ end
850
857
  end
851
858
 
852
859
  class StatementInterpreter < SubInterpreter
@@ -234,6 +234,7 @@ module C #:nodoc:
234
234
  def_delegator :interpreter, :notify_c99_for_stmt_ended
235
235
  def_delegator :interpreter, :notify_goto_stmt_evaled
236
236
  def_delegator :interpreter, :notify_return_stmt_evaled
237
+ def_delegator :interpreter, :notify_implicit_return_evaled
237
238
  def_delegator :interpreter, :notify_if_ctrlexpr_evaled
238
239
  def_delegator :interpreter, :notify_if_else_ctrlexpr_evaled
239
240
  def_delegator :interpreter, :notify_switch_ctrlexpr_evaled
@@ -102,6 +102,20 @@ module C #:nodoc:
102
102
  end
103
103
  end
104
104
 
105
+ class W0645 < PassiveMessageDetection
106
+ def initialize(context)
107
+ super
108
+ visitor = context[:c_visitor]
109
+ visitor.enter_kandr_function_definition += method(:check)
110
+ end
111
+
112
+ def check(node)
113
+ if node.type.parameter_types.any? { |type| type.void? }
114
+ W(:W0645, node.location)
115
+ end
116
+ end
117
+ end
118
+
105
119
  class W0685 < W0573
106
120
  def check(function_call_expression, function, arg_variables,
107
121
  result_variable)
@@ -142,6 +156,35 @@ module C #:nodoc:
142
156
  end
143
157
  end
144
158
 
159
+ class W0697 < PassiveMessageDetection
160
+ def initialize(context)
161
+ super
162
+ interp = context[:c_interpreter]
163
+ interp.on_function_started += method(:start_function)
164
+ interp.on_function_ended += method(:end_function)
165
+ interp.on_implicit_return_evaled += method(:check_implicit_return)
166
+ @current_function = nil
167
+ end
168
+
169
+ private
170
+ def start_function(function_definition, function)
171
+ @current_function = function_definition
172
+ end
173
+
174
+ def end_function(function_definition, function)
175
+ @current_function = nil
176
+ end
177
+
178
+ def check_implicit_return
179
+ return unless @current_function
180
+
181
+ unless @current_function.type.return_type.void?
182
+ W(:W0697,
183
+ @current_function.location, @current_function.identifier.value)
184
+ end
185
+ end
186
+ end
187
+
145
188
  class W0698 < PassiveMessageDetection
146
189
  def initialize(context)
147
190
  super
@@ -187,6 +230,45 @@ module C #:nodoc:
187
230
  end
188
231
  end
189
232
 
233
+ class W0700 < PassiveMessageDetection
234
+ def initialize(context)
235
+ super
236
+ interp = context[:c_interpreter]
237
+ interp.on_function_started += method(:start_function)
238
+ interp.on_function_ended += method(:end_function)
239
+ interp.on_return_stmt_evaled += method(:check_explicit_return)
240
+ interp.on_implicit_return_evaled += method(:check_implicit_return)
241
+ @current_function = nil
242
+ end
243
+
244
+ private
245
+ def start_function(function_definition, function)
246
+ @current_function = function_definition
247
+ end
248
+
249
+ def end_function(function_definition, function)
250
+ @current_function = nil
251
+ end
252
+
253
+ def check_explicit_return(return_stmt, result_variable)
254
+ return unless @current_function
255
+
256
+ if @current_function.implicitly_typed? && return_stmt.expression.nil?
257
+ W(:W0700,
258
+ @current_function.location, @current_function.identifier.value)
259
+ end
260
+ end
261
+
262
+ def check_implicit_return
263
+ return unless @current_function
264
+
265
+ if @current_function.implicitly_typed?
266
+ W(:W0700,
267
+ @current_function.location, @current_function.identifier.value)
268
+ end
269
+ end
270
+ end
271
+
190
272
  class W0711 < PassiveMessageDetection
191
273
  def initialize(context)
192
274
  super
@@ -552,5 +634,145 @@ module C #:nodoc:
552
634
  end
553
635
  end
554
636
 
637
+ class W1066 < PassiveMessageDetection
638
+ def initialize(context)
639
+ super
640
+ @interp = context[:c_interpreter]
641
+ @interp.on_explicit_conv_performed += method(:check)
642
+ @interp.on_function_started += method(:clear_rvalues)
643
+ @interp.on_additive_expr_evaled += method(:handle_additive)
644
+ @interp.on_multiplicative_expr_evaled += method(:handle_multiplicative)
645
+ @rvalues = nil
646
+ end
647
+
648
+ private
649
+ def check(cast_expression, original_variable, result_variable)
650
+ return unless @rvalues
651
+ return unless original_variable.type.floating?
652
+
653
+ case expression = @rvalues[original_variable]
654
+ when AdditiveExpression, MultiplicativeExpression
655
+ if original_variable.type.same_as?(from_type) &&
656
+ result_variable.type.same_as?(to_type)
657
+ W(message_id, expression.location)
658
+ end
659
+ end
660
+ end
661
+
662
+ def clear_rvalues(function_definition, function)
663
+ @rvalues = {}
664
+ end
665
+
666
+ def handle_additive(additive_expression,
667
+ lhs_variable, rhs_variable, result_variable)
668
+ memorize_rvalue_derivation(result_variable, additive_expression)
669
+ end
670
+
671
+ def handle_multiplicative(multiplicative_expression,
672
+ lhs_variable, rhs_variable, result_variable)
673
+ return if multiplicative_expression.operator.type == "%"
674
+ memorize_rvalue_derivation(result_variable, multiplicative_expression)
675
+ end
676
+
677
+ def memorize_rvalue_derivation(rvalue_holder, expression)
678
+ @rvalues[rvalue_holder] = expression if @rvalues
679
+ end
680
+
681
+ def from_type
682
+ @interp.float_type
683
+ end
684
+
685
+ def to_type
686
+ @interp.double_type
687
+ end
688
+
689
+ def message_id
690
+ self.class.name.sub(/\A.*::/, "").intern
691
+ end
692
+ end
693
+
694
+ class W1067 < W1066
695
+ private
696
+ def from_type
697
+ @interp.float_type
698
+ end
699
+
700
+ def to_type
701
+ @interp.long_double_type
702
+ end
703
+ end
704
+
705
+ class W1068 < W1066
706
+ private
707
+ def from_type
708
+ @interp.double_type
709
+ end
710
+
711
+ def to_type
712
+ @interp.long_double_type
713
+ end
714
+ end
715
+
716
+ class W1069 < PassiveMessageDetection
717
+ def initialize(context)
718
+ super
719
+ visitor = context[:c_visitor]
720
+ visitor.enter_ansi_function_definition += method(:enter_function)
721
+ visitor.leave_ansi_function_definition += method(:leave_function)
722
+ visitor.enter_kandr_function_definition += method(:enter_function)
723
+ visitor.leave_kandr_function_definition += method(:leave_function)
724
+ visitor.enter_if_else_statement += method(:enter_if_else_statement)
725
+ visitor.leave_if_else_statement += method(:leave_if_else_statement)
726
+ @if_else_statement_chain = []
727
+ end
728
+
729
+ private
730
+ def enter_function(function_definition)
731
+ @if_else_statement_chain = []
732
+ end
733
+
734
+ def leave_function(function_definition)
735
+ @if_else_statement_chain = []
736
+ end
737
+
738
+ def enter_if_else_statement(node)
739
+ @if_else_statement_chain.push(node)
740
+ if node.else_statement.kind_of?(IfStatement)
741
+ W(:W1069, @if_else_statement_chain.first.location)
742
+ end
743
+ end
744
+
745
+ def leave_if_else_statement(node)
746
+ @if_else_statement_chain.pop
747
+ end
748
+ end
749
+
750
+ class W1070 < W0781
751
+ private
752
+ def check(node)
753
+ if exec_path_num = @exec_path_nums.last and exec_path_num == 2
754
+ W(:W1070, node.location)
755
+ end
756
+ @exec_path_nums.pop
757
+ end
758
+
759
+ def add_exec_path(node)
760
+ @exec_path_nums[-1] += 1
761
+ end
762
+ end
763
+
764
+ class W1072 < PassiveMessageDetection
765
+ def initialize(context)
766
+ super
767
+ visitor = context[:c_visitor]
768
+ visitor.enter_goto_statement += method(:warn_goto)
769
+ end
770
+
771
+ private
772
+ def warn_goto(node)
773
+ W(:W1072, node.location)
774
+ end
775
+ end
776
+
555
777
  end
556
778
  end
@@ -596,6 +596,7 @@ module C #:nodoc:
596
596
  W0639.new(context),
597
597
  W0640.new(context),
598
598
  W0642.new(context),
599
+ W0645.new(context),
599
600
  W0653.new(context),
600
601
  W0654.new(context),
601
602
  W0655.new(context),
@@ -630,8 +631,10 @@ module C #:nodoc:
630
631
  W0684.new(context),
631
632
  W0685.new(context),
632
633
  W0686.new(context),
634
+ W0697.new(context),
633
635
  W0698.new(context),
634
636
  W0699.new(context),
637
+ W0700.new(context),
635
638
  W0703.new(context),
636
639
  W0704.new(context),
637
640
  W0705.new(context),
@@ -745,6 +748,12 @@ module C #:nodoc:
745
748
  W1063.new(context),
746
749
  W1064.new(context),
747
750
  W1065.new(context),
751
+ W1066.new(context),
752
+ W1067.new(context),
753
+ W1068.new(context),
754
+ W1069.new(context),
755
+ W1070.new(context),
756
+ W1072.new(context),
748
757
  W9001.new(context),
749
758
  W9003.new(context)
750
759
  ]
data/lib/adlint/c/type.rb CHANGED
@@ -7562,21 +7562,22 @@ module C #:nodoc:
7562
7562
  end
7563
7563
 
7564
7564
  def qualify_type(type, type_qualifiers, declarator, interpreter = nil)
7565
- type_qualifiers.each do |token|
7565
+ cvr_qualifiers = type_qualifiers.map { |token|
7566
7566
  case token.type
7567
- when :CONST
7568
- type = qualified_type(type, :const)
7569
- when :VOLATILE
7570
- type = qualified_type(type, :volatile)
7571
- when :RESTRICT
7572
- # TODO: Should support C99 features.
7567
+ when :CONST then :const
7568
+ when :VOLATILE then :volatile
7569
+ else
7570
+ # TODO: Should support C99 `restrict' qualifier.
7573
7571
  end
7574
- end
7575
-
7576
- return type unless declarator
7572
+ }.compact
7573
+ type = qualified_type(type, *cvr_qualifiers) unless cvr_qualifiers.empty?
7577
7574
 
7578
- decl_interp = DeclaratorInterpreter.new(self, interpreter, type)
7579
- declarator.accept(decl_interp)
7575
+ if declarator
7576
+ decl_interp = DeclaratorInterpreter.new(self, interpreter, type)
7577
+ declarator.accept(decl_interp)
7578
+ else
7579
+ type
7580
+ end
7580
7581
  end
7581
7582
 
7582
7583
  def create_members(struct_declarations)
@@ -32,9 +32,9 @@
32
32
  module AdLint #:nodoc:
33
33
 
34
34
  MAJOR_VERSION = 1
35
- MINOR_VERSION = 12
35
+ MINOR_VERSION = 14
36
36
  PATCH_VERSION = 0
37
- RELEASE_DATE = "2012-06-20"
37
+ RELEASE_DATE = "2012-07-04"
38
38
 
39
39
  TRAITS_SCHEMA_VERSION = "1.0.0"
40
40