Module: Necropsy::Bench::FindingFacts
- Defined in:
- lib/necropsy/bench/finding_facts.rb
Constant Summary collapse
- ACTIONABLE_CLASSIFICATIONS =
%i[unreachable unused].freeze
- UNKNOWN_BLOCKER_KINDS =
%i[ analyzer_failure ambiguity_limit_exceeded dynamic_dispatch evidence_collision dynamic_ancestry incomplete_analysis incomplete_source parse_failure parse_incomplete partial_dispatch reference_scope_incomplete resolution_conflict resolution_invalid unknown_dispatch unparsed_external_reference unsupported_refinement variable_eval ].freeze
- RULE_ROOT_REASONS =
%i[ callback_registered rails_component rails_migration rails_route rails_view_helper rails_view_reference ].freeze
- ORDINARY_DEFINITION_KINDS =
%i[def defs define_method].freeze
Class Method Summary collapse
- .actionable?(finding) ⇒ Boolean
- .category(finding) ⇒ Object
- .loc(finding) ⇒ Object
- .ratio(numerator, denominator) ⇒ Object
- .report_risk_counts(report) ⇒ Object
- .report_rule_counts(report) ⇒ Object
- .resolution_counts(report) ⇒ Object
- .risk_flags(finding) ⇒ Object
- .rule_hits(finding) ⇒ Object
- .tally(values) ⇒ Object
- .unknown?(finding) ⇒ Boolean
Class Method Details
.actionable?(finding) ⇒ Boolean
21 22 23 |
# File 'lib/necropsy/bench/finding_facts.rb', line 21 def actionable?(finding) ACTIONABLE_CLASSIFICATIONS.include?(finding.classification.to_sym) end |
.category(finding) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/necropsy/bench/finding_facts.rb', line 64 def category(finding) explicit = explicit_category(finding) return explicit if explicit blocker = finding.blockers.first return blocker.kind.to_s if blocker defined_via = finding.node.defined_via.to_sym return 'generated_method' unless ORDINARY_DEFINITION_KINDS.include?(defined_via) finding.classification.to_s end |
.loc(finding) ⇒ Object
25 26 27 28 29 30 31 |
# File 'lib/necropsy/bench/finding_facts.rb', line 25 def loc(finding) start_line = positive_integer(finding.node.line) end_line = positive_integer(finding.node.end_line) || start_line return 0 unless start_line [end_line - start_line + 1, 1].max end |
.ratio(numerator, denominator) ⇒ Object
112 113 114 |
# File 'lib/necropsy/bench/finding_facts.rb', line 112 def ratio(numerator, denominator) denominator.zero? ? 0.0 : (numerator.to_f / denominator).round(4) end |
.report_risk_counts(report) ⇒ Object
88 89 90 |
# File 'lib/necropsy/bench/finding_facts.rb', line 88 def report_risk_counts(report) tally(report.reportable_findings.flat_map { |finding| risk_flags(finding) }) end |
.report_rule_counts(report) ⇒ Object
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/necropsy/bench/finding_facts.rb', line 77 def report_rule_counts(report) finding_rules = report.reportable_findings.flat_map { |finding| rule_hits(finding) } root_rules = report.graph.entry_points.filter_map do |root| node = report.graph.nodes.exact(root.definition_id) next unless node && report_path?(report, node.file) root.reason.to_s if RULE_ROOT_REASONS.include?(root.reason.to_sym) end tally(finding_rules + root_rules) end |
.resolution_counts(report) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/necropsy/bench/finding_facts.rb', line 96 def resolution_counts(report) visible_call_site_ids = report.graph.call_sites.filter_map do |site| site.call_site_id if report_path?(report, site.file) end.to_set records = report.graph.resolution_records.select do |record| visible_call_site_ids.include?(record.resolution.call_site_id) end counts = records.map { |record| record.resolution.status.to_s }.tally { 'total' => records.length, 'complete' => counts.fetch('complete', 0), 'partial' => counts.fetch('partial', 0), 'unknown' => counts.fetch('unknown', 0) } end |
.risk_flags(finding) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/necropsy/bench/finding_facts.rb', line 37 def risk_flags(finding) node = finding.node flags = [] flags << 'public_or_protected_visibility' if %i[public protected].include?(node.visibility.to_sym) flags << 'generated_method' unless ORDINARY_DEFINITION_KINDS.include?(node.defined_via.to_sym) flags << 'no_owner' if node.owner.to_s.empty? flags << 'test_definition' if node.test flags << 'analysis_incomplete' if finding.blockers.any? flags << 'duplicate_or_redefinition' if finding.blockers.any? do |blocker| blocker.kind.to_sym == :duplicate_definition end flags.uniq.sort end |
.rule_hits(finding) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/necropsy/bench/finding_facts.rb', line 51 def rule_hits(finding) evidence_rules = finding.evidences.flat_map do |evidence| = stringify_keys(evidence.) values = [['rule_id'], ['rule'], ['rules']] values.flatten.compact end blocker_rules = finding.blockers.filter_map do |blocker| = stringify_keys(blocker.) ['rule_id'] || ['rule'] end (evidence_rules + blocker_rules).map(&:to_s).reject(&:empty?).uniq.sort end |
.tally(values) ⇒ Object
92 93 94 |
# File 'lib/necropsy/bench/finding_facts.rb', line 92 def tally(values) values.map(&:to_s).reject(&:empty?).tally.sort.to_h end |
.unknown?(finding) ⇒ Boolean
33 34 35 |
# File 'lib/necropsy/bench/finding_facts.rb', line 33 def unknown?(finding) finding.blockers.any? { |blocker| unknown_blocker?(blocker) } end |