pronto-clang_tidy 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 258553456e56ce657bf44611c40fc43d418c51600d86b0e30e11a18abe542d8a
4
- data.tar.gz: 6853bf8719af3147fb58b44242fc5a9a311284221a2d5aab1423227d64193c05
3
+ metadata.gz: 756bd9000c3003b901e0fbd36a4771c26a4fbbaec2040079f7ebcd8f21f260fc
4
+ data.tar.gz: bc48d8809b0f631cf83c6d51bb89c61350eaca0f7799d353a19e284d49012fdc
5
5
  SHA512:
6
- metadata.gz: 8aa32a8b3bedaaeb47a6adf31a5fe643073e5206470d58f34505354507e68f5fa8190cd5de32399e236ea61b0c7c078c2ee4564d0381dec372a6986a69a07b92
7
- data.tar.gz: ad0e9cb98a09fc903d3cb98b441b31a81e5f8417b0809c36f0cc46151f8f4688330229e4164cb3a7d95ca01ca714a84b274861f6d1bb3412aa57c939c0372180
6
+ metadata.gz: 45f6b218f0e733d0f56d9ee533320a8fc1b6af5f134d3b27db66be0d30fb66288442eb1264dd719096c5420981abd7603a5a67210a404a499dbd52c3852e3749
7
+ data.tar.gz: 70ad8726b3a64a9b9061a1df7af3a58b5c13809847b6e9778f3e10af6e490d705f20f7ef15fa388dca44ff4abe472ced3f2e3e1aa7c0818843ec847e4cfb4cfd
@@ -1,84 +1,2 @@
1
1
  require_relative 'clang_tidy/version'
2
- require 'pronto'
3
-
4
- module Pronto
5
- class ClangTidyRunner < Runner
6
- def run
7
- offences = read_clang_tidy_output
8
- return [] if no_patches? || offences.length.zero?
9
- # loop through all offences in clang-tidy output
10
- offences.map do |offence|
11
- # find the patch that corresponds to the current offence
12
- patch = patch_for(offence.file)
13
- next if patch.nil?
14
- # generate a message for the corresponding added_line in the patch
15
- message_for(patch, offence)
16
- # Header warnings are repeated for every compilation unit that includes
17
- # them. Use uniq to ignore repeated messages
18
- end.flatten.compact.uniq
19
- end
20
-
21
- private
22
-
23
- def message_for(patch, offence)
24
- line = patch.added_lines.find do |added_line|
25
- added_line.new_lineno == offence.lineno
26
- end
27
- new_message(offence, line) unless line.nil?
28
- end
29
-
30
- def no_patches?
31
- !@patches || @patches.count.zero?
32
- end
33
-
34
- def patch_for(filename)
35
- @patches.find do |p|
36
- p.new_file_full_path == Pathname.new(filename)
37
- end
38
- end
39
-
40
- def new_message(offence, line)
41
- path = line.patch.delta.new_file[:path]
42
- Message.new(path, line, pronto_level(offence.level), offence.msg, nil,
43
- self.class)
44
- end
45
-
46
- def pronto_level(clang_level)
47
- case clang_level
48
- when :warning
49
- :warning
50
- when :error
51
- :error
52
- when :fatal
53
- :fatal
54
- else
55
- :info
56
- end
57
- end
58
-
59
- # reads clang-tidy output file and returns an array of offences
60
- def read_clang_tidy_output
61
- unless FileTest.file? clang_tidy_output_file
62
- puts 'WARN: pronto-clang_tidy: clang-tidy output file not found'
63
- return []
64
- end
65
- parse_clang_tidy_output File.read(clang_tidy_output_file)
66
- end
67
-
68
- # parses clang-tidy output and returns a list of offences
69
- def parse_clang_tidy_output(output)
70
- regexp = Regexp.new '(?<filename>^/[^:]+):(?<line>\d+):' \
71
- '(?<col>\d+): (?<level>[^:]+): (?<message>.+$)'
72
- offences = []
73
- output.scan regexp do |filename, line, _col, level, message|
74
- offences << OpenStruct.new(file: filename, lineno: line.to_i,
75
- level: level.to_sym, msg: message)
76
- end
77
- offences
78
- end
79
-
80
- def clang_tidy_output_file
81
- ENV['PRONTO_CLANG_TIDY_OUTFILE'] || 'clang-tidy.out'
82
- end
83
- end
84
- end
2
+ require_relative 'clang_tidy_runner'
@@ -0,0 +1,39 @@
1
+ require 'pathname'
2
+
3
+ module Pronto
4
+ module ClangTidy
5
+ # a class that represents a single diagnostic emitted by clang-tidy
6
+ class Diagnostic
7
+ attr_reader :filename, :line_no, :col_no, :level, :message, :hints
8
+ def initialize(filename, line_no, col_no, level, message)
9
+ @filename = abs(filename)
10
+ @line_no = line_no.to_i
11
+ @col_no = col_no.to_i
12
+ @level = level.to_sym
13
+ @message = message
14
+ @hints = ''
15
+ end
16
+
17
+ def formatted_filename
18
+ # output a relative path when filename is inside working directory
19
+ if filename.to_s.start_with?(abs(Pathname.pwd).to_s)
20
+ filename.relative_path_from(Pathname.pwd)
21
+ else
22
+ filename.to_s # absolute otherwise
23
+ end
24
+ end
25
+
26
+ def format_diagnostic
27
+ "#{formatted_filename}:#{line_no}:#{col_no}: #{level}: #{message}\n" \
28
+ "```\n#{hints}```\n"
29
+ end
30
+
31
+ private
32
+
33
+ # converts the given String or Pathname to an absolute Pathname
34
+ def abs(pathname)
35
+ Pathname.new File.absolute_path Pathname.new pathname
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ require_relative 'diagnostic'
2
+
3
+ module Pronto
4
+ module ClangTidy
5
+ # a class that groups multiple related diagnostics together
6
+ #
7
+ # Clang uses NOTE-level diagnostics to staple more information onto
8
+ # previous diagnostics. The Offence class groups a diagnostic along with
9
+ # all subsequent NOTE-level diagnostics into a single entity.
10
+ class Offence
11
+ attr_reader :main, :notes
12
+ def initialize(main_diagnostic)
13
+ @main = main_diagnostic
14
+ @notes = []
15
+ end
16
+
17
+ def <<(note_diagnostic)
18
+ @notes << note_diagnostic
19
+ end
20
+
21
+ # the message to be attached to the main diagnostic's line
22
+ def main_message
23
+ result = "#{main.message}\n"
24
+ notes.each do |note|
25
+ result << note.format_diagnostic
26
+ end
27
+ result
28
+ end
29
+
30
+ # the message to be attached to any of the notes' lines
31
+ #
32
+ # this is used only when the main diagnostic's line is not changed
33
+ def note_message
34
+ result = main.format_diagnostic
35
+ notes.each do |note|
36
+ result << note.format_diagnostic
37
+ end
38
+ result
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,53 @@
1
+ module Pronto
2
+ module ClangTidy
3
+ # a class that provides functions to parse a clang-tidy output file and
4
+ # returns an array of Offence objects
5
+ class Parser
6
+ def initialize(output_filename)
7
+ @output_filename = output_filename
8
+ end
9
+
10
+ # reads clang-tidy output file and returns an array of offences
11
+ def read_clang_tidy_output
12
+ unless FileTest.file? @output_filename
13
+ puts 'WARN: pronto-clang_tidy: clang-tidy output file not found'
14
+ return []
15
+ end
16
+ parse_clang_tidy_output File.read(@output_filename)
17
+ end
18
+
19
+ private
20
+
21
+ # parses clang-tidy output and returns a list of offences
22
+ def parse_clang_tidy_output(output)
23
+ # a regular expression that matches diagnostics' headers
24
+ header_regexp = Regexp.new '(?<filename>^/[^:]+):(?<line_no>\d+):' \
25
+ '(?<col_no>\d+): (?<level>[^:]+): ' \
26
+ '(?<message>.+$)'
27
+ diagnostics = []
28
+ output.each_line do |line|
29
+ if (match_data = header_regexp.match(line))
30
+ diagnostics << Diagnostic.new(*match_data.captures)
31
+ else
32
+ diagnostics.last.hints << line unless diagnostics.empty?
33
+ end
34
+ end
35
+ group_diagnostics(diagnostics)
36
+ end
37
+
38
+ # turns an array of diagnostics into an array of offences by grouping
39
+ # note-level diagnostics with their corresponding diagnostic
40
+ def group_diagnostics(diags)
41
+ offences = []
42
+ diags.each do |diag|
43
+ if diag.level != :note
44
+ offences << Offence.new(diag)
45
+ else
46
+ offences.last << diag unless offences.empty?
47
+ end
48
+ end
49
+ offences
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,5 +1,5 @@
1
1
  module Pronto
2
2
  module ClangTidy
3
- VERSION = '0.9.2'.freeze
3
+ VERSION = '0.9.3'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,87 @@
1
+ require 'pronto'
2
+ require_relative 'clang_tidy/diagnostic'
3
+ require_relative 'clang_tidy/offence'
4
+ require_relative 'clang_tidy/parser'
5
+
6
+ Diagnostic = ::Pronto::ClangTidy::Diagnostic
7
+ Offence = ::Pronto::ClangTidy::Offence
8
+ Parser = ::Pronto::ClangTidy::Parser
9
+
10
+ module Pronto
11
+ class ClangTidyRunner < Runner
12
+ def run
13
+ offences = Parser.new(clang_tidy_output_file).read_clang_tidy_output
14
+ return [] if no_patches? || offences.length.zero?
15
+ # loop through all offences in clang-tidy output
16
+ offences.map do |offence|
17
+ build_message_for(offence)
18
+ # Header warnings are repeated for every compilation unit that includes
19
+ # them. Use uniq to ignore repeated messages
20
+ end.flatten.compact.uniq
21
+ end
22
+
23
+ private
24
+
25
+ def no_patches?
26
+ !@patches || @patches.count.zero?
27
+ end
28
+
29
+ # creates a new pronto message for offence
30
+ def build_message_for(offence)
31
+ # find the line for the main diag in the current offence
32
+ main_line = find_line_for_diag(offence.main)
33
+ # if the main diagnostic in the offence points to a changed line
34
+ if main_line
35
+ new_message(main_line, offence.main.level, offence.main_message)
36
+ else
37
+ # try to find a note from the offence that belongs to changed a line
38
+ note_line = find_first_line_for_diags(offence.notes)
39
+ new_message(note_line, offence.main.level, offence.note_message)
40
+ end
41
+ end
42
+
43
+ # searches through patches for the diagnostic's line and returns it
44
+ # returns nil if the line was not changed
45
+ def find_line_for_diag(diag)
46
+ file_patch = @patches.find do |patch|
47
+ patch.new_file_full_path == Pathname.new(diag.filename)
48
+ end
49
+ return nil if file_patch.nil?
50
+ file_patch.added_lines.find do |added_line|
51
+ added_line.new_lineno == diag.line_no
52
+ end
53
+ end
54
+
55
+ # searches through the diags_array to find a diag that points to a changed
56
+ # line and returns that line
57
+ # returns nil when none of the diags point to a changed line
58
+ def find_first_line_for_diags(diags_array)
59
+ diags_array.map { |diag| find_line_for_diag(diag) }
60
+ .compact.first
61
+ end
62
+
63
+ def new_message(line, offence_level, offence_message)
64
+ return nil if line.nil?
65
+ path = line.patch.delta.new_file[:path]
66
+ Message.new(path, line, pronto_level(offence_level),
67
+ offence_message, nil, self.class)
68
+ end
69
+
70
+ def pronto_level(clang_level)
71
+ case clang_level
72
+ when :warning
73
+ :warning
74
+ when :error
75
+ :error
76
+ when :fatal
77
+ :fatal
78
+ else
79
+ :info
80
+ end
81
+ end
82
+
83
+ def clang_tidy_output_file
84
+ ENV['PRONTO_CLANG_TIDY_OUTFILE'] || 'clang-tidy.out'
85
+ end
86
+ end
87
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pronto-clang_tidy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Jabbour
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-24 00:00:00.000000000 Z
11
+ date: 2018-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pronto
@@ -82,7 +82,11 @@ files:
82
82
  - README.md
83
83
  - Rakefile
84
84
  - lib/pronto/clang_tidy.rb
85
+ - lib/pronto/clang_tidy/diagnostic.rb
86
+ - lib/pronto/clang_tidy/offence.rb
87
+ - lib/pronto/clang_tidy/parser.rb
85
88
  - lib/pronto/clang_tidy/version.rb
89
+ - lib/pronto/clang_tidy_runner.rb
86
90
  - pronto-clang_tidy.gemspec
87
91
  homepage: https://github.com/micjabbour/pronto-clang_tidy
88
92
  licenses: