adlint 3.0.4 → 3.0.8

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 (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)