lib/cc/engine/analyzers/violation.rb
# frozen_string_literal: true
require "cc/engine/analyzers/sexp_lines"
require "cc/engine/analyzers/violation_read_up"
require "digest"
module CC
module Engine
module Analyzers
class Violation
def initialize(language_strategy:, identical:, current_sexp:, other_sexps:)
@language_strategy = language_strategy
@identical = identical
@current_sexp = current_sexp
@other_sexps = other_sexps
end
def format
{
"type": "issue",
"check_name": check_name,
"description": description,
"categories": ["Duplication"],
"location": format_location,
"remediation_points": calculate_points,
"other_locations": format_other_locations,
"content": content_body,
"fingerprint": fingerprint,
"severity": calculate_severity,
}
end
def report_name
"#{current_sexp.file}-#{current_sexp.line}"
end
def mass
current_sexp.mass
end
def occurrences
other_sexps.count
end
def total_occurrences
occurrences + 1
end
def identical?
@identical
end
def check_name
"#{duplication_type}-code"
end
def fingerprint_check_name
"#{duplication_type.capitalize} code"
end
private
attr_reader :language_strategy, :other_sexps, :current_sexp
def calculate_points
@calculate_points ||= language_strategy.calculate_points(self)
end
def points_across_occurrences
calculate_points * total_occurrences
end
def calculate_severity
language_strategy.calculate_severity(points_across_occurrences)
end
def format_location
format_sexp(current_sexp)
end
def format_other_locations
other_sexps.map do |sexp|
format_sexp(sexp)
end
end
def format_sexp(sexp)
if language_strategy.use_sexp_lines?
lines = SexpLines.new(sexp)
{
"path": sexp.file.gsub(%r{^\./}, ""),
"lines": {
"begin": lines.begin_line,
"end": lines.end_line,
},
}
else
{
"path": sexp.file.gsub(%r{^\./}, ""),
"lines": {
"begin": sexp.line,
"end": sexp.end_line,
},
}
end
end
def content_body
@_content_body ||= { "body": ViolationReadUp.new(mass).contents }
end
def fingerprint
digest = Digest::MD5.new
digest << current_sexp.file
digest << "-"
digest << current_sexp.mass.to_s
digest << "-"
digest << fingerprint_check_name
digest.to_s
end
def duplication_type
if identical?
"identical"
else
"similar"
end
end
def description
"#{duplication_type.capitalize} blocks of code found in #{total_occurrences} locations. Consider refactoring."
end
end
end
end
end