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 +4 -4
- data/lib/pronto/clang_tidy.rb +1 -83
- data/lib/pronto/clang_tidy/diagnostic.rb +39 -0
- data/lib/pronto/clang_tidy/offence.rb +42 -0
- data/lib/pronto/clang_tidy/parser.rb +53 -0
- data/lib/pronto/clang_tidy/version.rb +1 -1
- data/lib/pronto/clang_tidy_runner.rb +87 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 756bd9000c3003b901e0fbd36a4771c26a4fbbaec2040079f7ebcd8f21f260fc
|
4
|
+
data.tar.gz: bc48d8809b0f631cf83c6d51bb89c61350eaca0f7799d353a19e284d49012fdc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45f6b218f0e733d0f56d9ee533320a8fc1b6af5f134d3b27db66be0d30fb66288442eb1264dd719096c5420981abd7603a5a67210a404a499dbd52c3852e3749
|
7
|
+
data.tar.gz: 70ad8726b3a64a9b9061a1df7af3a58b5c13809847b6e9778f3e10af6e490d705f20f7ef15fa388dca44ff4abe472ced3f2e3e1aa7c0818843ec847e4cfb4cfd
|
data/lib/pronto/clang_tidy.rb
CHANGED
@@ -1,84 +1,2 @@
|
|
1
1
|
require_relative 'clang_tidy/version'
|
2
|
-
|
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
|
@@ -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.
|
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-
|
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:
|