adlint 3.0.4 → 3.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/ChangeLog +374 -13
  2. data/INSTALL +1 -3
  3. data/MANIFEST +12 -0
  4. data/NEWS +30 -4
  5. data/README +0 -4
  6. data/TODO +2 -1
  7. data/etc/mesg.d/c_builtin/en_US/messages.yml +2 -2
  8. data/etc/mesg.d/c_builtin/ja_JP/messages.yml +2 -2
  9. data/etc/mesg.d/core/en_US/messages.yml +5 -1
  10. data/etc/mesg.d/core/ja_JP/messages.yml +5 -1
  11. data/features/code_check/W0422.feature +128 -0
  12. data/features/code_check/W0491.feature +57 -0
  13. data/features/code_check/W0492.feature +80 -0
  14. data/features/code_check/W0542.feature +20 -0
  15. data/features/code_check/W0580.feature +25 -0
  16. data/features/code_check/W0610.feature +36 -0
  17. data/features/code_check/W0642.feature +67 -0
  18. data/features/code_check/W0786.feature +39 -0
  19. data/features/code_check/W0830.feature +27 -0
  20. data/features/code_check/W1047.feature +72 -0
  21. data/features/code_check/W9003.feature +22 -0
  22. data/features/code_extraction/TODO +1 -0
  23. data/features/metric_measurement/TODO +1 -0
  24. data/lib/adlint/analyzer.rb +2 -2
  25. data/lib/adlint/cc1/ctrlexpr.rb +27 -6
  26. data/lib/adlint/cc1/domain.rb +72 -12
  27. data/lib/adlint/cc1/enum.rb +4 -0
  28. data/lib/adlint/cc1/expr.rb +31 -29
  29. data/lib/adlint/cc1/interp.rb +45 -56
  30. data/lib/adlint/cc1/lexer.rb +26 -5
  31. data/lib/adlint/cc1/mediator.rb +35 -6
  32. data/lib/adlint/cc1/object.rb +62 -19
  33. data/lib/adlint/cc1/parser.rb +948 -904
  34. data/lib/adlint/cc1/parser.y +59 -29
  35. data/lib/adlint/cc1/phase.rb +6 -8
  36. data/lib/adlint/cc1/syntax.rb +70 -17
  37. data/lib/adlint/cc1/util.rb +4 -4
  38. data/lib/adlint/code.rb +16 -6
  39. data/lib/adlint/cpp/eval.rb +31 -25
  40. data/lib/adlint/cpp/lexer.rb +11 -5
  41. data/lib/adlint/cpp/macro.rb +34 -7
  42. data/lib/adlint/cpp/phase.rb +8 -8
  43. data/lib/adlint/error.rb +6 -0
  44. data/lib/adlint/exam/c_builtin/cc1_check.rb +557 -594
  45. data/lib/adlint/exam/c_builtin/cc1_check_shima.rb +72 -72
  46. data/lib/adlint/exam/c_builtin/cc1_code.rb +72 -52
  47. data/lib/adlint/exam/c_builtin/cc1_metric.rb +131 -131
  48. data/lib/adlint/exam/c_builtin/cpp_check.rb +48 -48
  49. data/lib/adlint/exam/c_builtin/cpp_check_shima.rb +2 -2
  50. data/lib/adlint/exam/c_builtin/cpp_code.rb +21 -21
  51. data/lib/adlint/exam/c_builtin/ld_check.rb +88 -87
  52. data/lib/adlint/exam/c_builtin/ld_metric.rb +4 -5
  53. data/lib/adlint/exam/c_builtin.rb +6 -6
  54. data/lib/adlint/ld/object.rb +269 -186
  55. data/lib/adlint/ld/phase.rb +19 -19
  56. data/lib/adlint/ld/typedef.rb +7 -7
  57. data/lib/adlint/ld/util.rb +25 -17
  58. data/lib/adlint/location.rb +6 -1
  59. data/lib/adlint/memo.rb +66 -13
  60. data/lib/adlint/prelude.rb +2 -2
  61. data/lib/adlint/report.rb +13 -14
  62. data/lib/adlint/util.rb +1 -1
  63. data/lib/adlint/version.rb +2 -2
  64. data/share/doc/Makefile +6 -2
  65. data/share/doc/c99gram.dot +502 -0
  66. data/share/doc/c99gram.pdf +0 -0
  67. data/share/doc/developers_guide_ja.html +4 -3
  68. data/share/doc/developers_guide_ja.texi +2 -1
  69. data/share/doc/users_guide_en.html +9 -9
  70. data/share/doc/users_guide_en.texi +7 -7
  71. data/share/doc/users_guide_ja.html +9 -9
  72. data/share/doc/users_guide_ja.texi +7 -7
  73. metadata +14 -2
@@ -363,24 +363,27 @@ module Cpp #:nodoc:
363
363
  end
364
364
  discard_extra_tokens_until_newline(pp_ctxt)
365
365
  PPTokensNormalizer.normalize(pp_toks, pp_ctxt)
366
- return nil if pp_toks.tokens.empty?
367
- case param = pp_toks.tokens.map { |tok| tok.value }.join
368
- when /\A".*"\z/
369
- usr_include_line = UserIncludeLine.new(
370
- keyword, Token.new(:USR_HEADER_NAME, param,
371
- pp_toks.tokens.first.location),
372
- pp_ctxt.include_depth)
373
- include_first_user_header(usr_include_line, pp_ctxt)
374
- return usr_include_line
375
- when /\A<.*>\z/
376
- sys_include_line = SystemIncludeLine.new(
377
- keyword, Token.new(:SYS_HEADER_NAME, param,
378
- pp_toks.tokens.first.location),
379
- pp_ctxt.include_depth)
380
- include_first_system_header(sys_include_line, pp_ctxt)
381
- return sys_include_line
366
+ unless pp_toks.tokens.empty?
367
+ case param = pp_toks.tokens.map { |tok| tok.value }.join
368
+ when /\A".*"\z/
369
+ usr_include_line = UserIncludeLine.new(
370
+ keyword, Token.new(:USR_HEADER_NAME, param,
371
+ pp_toks.tokens.first.location),
372
+ pp_ctxt.include_depth)
373
+ include_first_user_header(usr_include_line, pp_ctxt)
374
+ return usr_include_line
375
+ when /\A<.*>\z/
376
+ sys_include_line = SystemIncludeLine.new(
377
+ keyword, Token.new(:SYS_HEADER_NAME, param,
378
+ pp_toks.tokens.first.location),
379
+ pp_ctxt.include_depth)
380
+ include_first_system_header(sys_include_line, pp_ctxt)
381
+ return sys_include_line
382
+ end
382
383
  end
383
- nil
384
+ E(:E0017, keyword.location)
385
+ raise IllformedIncludeDirectiveError.new(
386
+ keyword.location, pp_ctxt.msg_fpath, pp_ctxt.log_fpath)
384
387
  end
385
388
 
386
389
  def macro_include_next_line(pp_ctxt, keyword)
@@ -815,10 +818,10 @@ module Cpp #:nodoc:
815
818
  on_extra_tokens_found.invoke(extra_toks)
816
819
  end
817
820
 
818
- def handle_unterminated_block_comment(pp_ctxt, loc)
821
+ def handle_unterminated_block_comment(loc)
819
822
  E(:E0016, loc)
820
- raise UnterminatedCommentError.new(loc, pp_ctxt.msg_fpath,
821
- pp_ctxt.log_fpath)
823
+ raise UnterminatedCommentError.new(loc, @pp_ctxt.msg_fpath,
824
+ @pp_ctxt.log_fpath)
822
825
  end
823
826
 
824
827
  extend Forwardable
@@ -879,12 +882,15 @@ module Cpp #:nodoc:
879
882
  end
880
883
 
881
884
  def top_token
882
- return nil if @lexer_stack.empty?
883
- unless tok = @lexer_stack.last.top_token
884
- @lexer_stack.pop
885
- top_token
885
+ unless @lexer_stack.empty?
886
+ unless tok = @lexer_stack.last.top_token
887
+ @lexer_stack.pop
888
+ top_token
889
+ else
890
+ tok
891
+ end
886
892
  else
887
- tok
893
+ nil
888
894
  end
889
895
  end
890
896
 
@@ -165,19 +165,25 @@ module Cpp #:nodoc:
165
165
 
166
166
  def scan_block_comment(cont)
167
167
  comment = ""
168
- block_depth = 0
168
+ nest_depth = 0
169
169
  until cont.empty?
170
170
  loc = cont.location
171
171
  case
172
- when cont.scan(/\/\*/)
173
- block_depth += 1
172
+ when nest_depth == 0 && cont.scan(/\/\*/)
173
+ nest_depth = 1
174
174
  comment += "/*"
175
- notify_nested_block_comment_found(loc) if block_depth > 1
175
+ when nest_depth > 0 && cont.check(/\/\*\//)
176
+ comment += cont.scan(/\//)
177
+ when nest_depth > 0 && cont.check(/\/\*/)
178
+ nest_depth += 1
179
+ comment += cont.scan(/\/\*/)
180
+ notify_nested_block_comment_found(loc)
176
181
  when cont.scan(/\*\//)
177
182
  comment += "*/"
178
183
  break
184
+ when nest_depth == 0
185
+ return nil
179
186
  else
180
- return nil if block_depth == 0
181
187
  if scanned = cont.scan(/.*?(?=\/\*|\*\/)/m)
182
188
  comment += scanned
183
189
  else
@@ -343,26 +343,53 @@ module Cpp #:nodoc:
343
343
  # order of evaluation of ## operators is unspecified.
344
344
 
345
345
  if lhs = res_toks.pop
346
- if rhs = arg_toks.first
346
+ unless arg_toks.empty?
347
347
  # NOTE: To avoid syntax error when the concatenated token can be
348
348
  # retokenize to two or more tokens.
349
- new_toks = StringToPPTokensLexer.new(lhs.value + rhs.value).execute
349
+ unlexed_arg = unlex_tokens(arg_toks)
350
+ new_toks = StringToPPTokensLexer.new(lhs.value + unlexed_arg).execute
350
351
  new_toks.map! do |tok|
351
352
  ReplacedToken.new(tok.type, tok.value, expansion_loc,
352
353
  tok.type_hint, false)
353
354
  end
354
355
  res_toks.concat(new_toks)
355
- res_toks.concat(arg_toks[1..-1].map { |tok|
356
- ReplacedToken.new(tok.type, tok.value, expansion_loc,
357
- tok.type_hint, false)
358
- })
356
+
357
+ macro_tbl.notify_sharpsharp_operator_evaled(
358
+ lhs, Token.new(:MACRO_ARG, unlexed_arg, arg_toks.first.location),
359
+ new_toks)
359
360
  else
360
361
  new_toks = [ReplacedToken.new(lhs.type, lhs.value, expansion_loc,
361
362
  lhs.type_hint, false)]
362
363
  res_toks.concat(new_toks)
363
364
  end
365
+ end
366
+ end
367
+
368
+ def unlex_tokens(arg_toks)
369
+ # NOTE: To regenerate source string from pp_tokens in preparation for
370
+ # the argument substitution.
364
371
 
365
- macro_tbl.notify_sharpsharp_operator_evaled(lhs, rhs, new_toks)
372
+ # 6.10.3 Macro replacement
373
+ #
374
+ # Semantics
375
+ #
376
+ # 11 The sequence of preprocessing tokens bounded by the outside-most
377
+ # matching parentheses forms the list of arguments for the
378
+ # function-like macro. The individual arguments within the list are
379
+ # separated by comma preprocessing tokens, but comma preprocessing
380
+ # tokens between matching inner parentheses do not separate arguments.
381
+ # If there are sequences of preprocessing tokens within the list of
382
+ # arguments that would otherwise act as preprocessing directives, the
383
+ # behavior is undefined.
384
+
385
+ arg_toks.each_cons(2).reduce(arg_toks.first.value) do |str, (lhs, rhs)|
386
+ lhs_loc, rhs_loc = lhs.location, rhs.location
387
+ if lhs_loc.line_no == rhs_loc.line_no
388
+ tok_gap = rhs_loc.column_no - lhs_loc.column_no - lhs.value.length
389
+ str + " " * [tok_gap, 0].max + rhs.value
390
+ else
391
+ "#{str} #{rhs.value}"
392
+ end
366
393
  end
367
394
  end
368
395
  end
@@ -52,10 +52,10 @@ module Cpp #:nodoc:
52
52
  private
53
53
  def do_execute(phase_ctxt, *)
54
54
  root_src = phase_ctxt[:sources].first
55
- phase_ctxt[:cc1_source] = PreprocessedSource.new(root_src)
56
- phase_ctxt[:cpp_macro_table] = MacroTable.new
57
- phase_ctxt[:cpp_interpreter] = Preprocessor.new
58
- phase_ctxt[:cpp_visitor] = SyntaxTreeMulticastVisitor.new
55
+ phase_ctxt[:cc1_source] = PreprocessedSource.new(root_src)
56
+ phase_ctxt[:cpp_macro_table] = MacroTable.new
57
+ phase_ctxt[:cpp_interpreter] = Preprocessor.new
58
+ phase_ctxt[:cpp_ast_traversal] = SyntaxTreeMulticastVisitor.new
59
59
  register_annotation_parser
60
60
  end
61
61
 
@@ -105,7 +105,7 @@ module Cpp #:nodoc:
105
105
  else
106
106
  init_header = EmptySource.new
107
107
  end
108
- phase_ctxt[:cpp_syntax_tree] =
108
+ phase_ctxt[:cpp_ast] =
109
109
  phase_ctxt[:cpp_interpreter].execute(pp_ctxt, init_header)
110
110
  end
111
111
 
@@ -116,13 +116,13 @@ module Cpp #:nodoc:
116
116
  else
117
117
  init_header = EmptySource.new
118
118
  end
119
- phase_ctxt[:cpp_syntax_tree].concat(
119
+ phase_ctxt[:cpp_ast].concat(
120
120
  phase_ctxt[:cpp_interpreter].execute(pp_ctxt, init_header))
121
121
  end
122
122
 
123
123
  def process_target_source(phase_ctxt, pp_ctxt)
124
124
  root_src = phase_ctxt[:sources].first
125
- phase_ctxt[:cpp_syntax_tree].concat(
125
+ phase_ctxt[:cpp_ast].concat(
126
126
  phase_ctxt[:cpp_interpreter].execute(pp_ctxt, root_src))
127
127
  end
128
128
  end
@@ -145,7 +145,7 @@ module Cpp #:nodoc:
145
145
 
146
146
  private
147
147
  def do_execute(phase_ctxt, *)
148
- phase_ctxt[:cpp_syntax_tree].accept(phase_ctxt[:cpp_visitor])
148
+ phase_ctxt[:cpp_ast].accept(phase_ctxt[:cpp_ast_traversal])
149
149
  end
150
150
  end
151
151
 
data/lib/adlint/error.rb CHANGED
@@ -151,6 +151,12 @@ module AdLint #:nodoc:
151
151
  end
152
152
  end
153
153
 
154
+ class IllformedIncludeDirectiveError < FatalError
155
+ def initialize(loc, msg_fpath, log_fpath)
156
+ super("#include expects a filename", loc, msg_fpath, log_fpath)
157
+ end
158
+ end
159
+
154
160
  class UnterminatedCommentError < FatalError
155
161
  def initialize(loc, msg_fpath, log_fpath)
156
162
  super("unterminated comment block found.", loc, msg_fpath, log_fpath)