pronto-clang_tidy 0.9.2 → 0.9.3

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.
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: