adlint 1.12.0 → 1.14.0

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