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