NAME

Perl::Critic::Policy::Generic::External - Dynamically ingest violations from external files, Copilot, ChatGPT, Claude

DESCRIPTION

Perl::Critic is already used by organizations to analyze and track code improvement needs. External tooling that performs static analysis of code can be integrated into the same workflows by producing data that is directly available when Perl::Critic analyzes each file.

Example

Suppose an external scanner identifies the following concerns and categorizes them as:

# Description for BuiltinFunctions::UseSay:  Use 'say' instead of print \n.
# Explanation for BuiltinFunctions::UseSay:  ... so using 'say' is more common.
a.pl   3   0   BuiltinFunctions   UseSay
a.pl   3   6   BuiltinFunctions   UseSprintf

When Generic::External is configured to use that source file, it yields:

perlcritic --verbose '%m in %f %l:%c (%p)\n' a.pl

Use 'say' instead of print \n in a.pl 3:1 (BuiltinFunctions::UseSay)
UseSprintf in a.pl 3:6 (BuiltinFunctions::UseSprintf)

CONFIGURATION

filetsv

A tab-separated file can be used to identify files with violations:

[Generic::External]
filetsv = filename.tsv

The general format of the file should be tab separated columns:

source line column Category Policy

The violations can appear in any order. Note that the file may be scanned multiple times during perlcritic execution.

Descriptions and Explanations may be included in the file:

# Description for Category::Policy:  Here is some description.
# Explanation for Category::Policy:  Here is some explanation.

Each is limited to a single line and the category and policy must exactly match the resulting violation package name.

VIOLATIONS

Category and Policy

Each violation must include a Category and Policy, which will associate with a violation for Perl::Critic::Policy::Category::Policy. Names must match /[A-Za-z][A-Za-z0-9_]*/ as with regular Perl package names. Names are first stripped of all extra characters so "Some Category" will become "SomeCategory".

Filenames

At this time, filenames must match exactly. Any file that perlcritic scans of the form ./source.ext will check external references only for source.ext.

Violation location

Violations will generally emit based on the line and column as:

* Exactly at the matching token if it exists within the document.

* With this token if the next token would be past the violation.

If a violation has a column number of zero, it will emit with the first token on that line.

TODO

The following appear in no particular priority order.

filetsv

Subject to change... Currently the file is scanned when each source file is checked by perlcritic. To reduce unnecessary reads, the full file list is loaded on first read; any document being scanned by Perl::Critic will be skipped if the filename didn't appear in the file. Otherwise the file will be fully read for matching lines. This approach is primarily to avoid the memory overhead of fully loading the file in the first pass, since large repositories may have 10--100MB of violations per 1000 files. Options include loading it and not caring, always rereading, or setting some configurable limit at which rereading is enabled.

Input

Add support for: filejson, cli.

After the performance/memory question has been answered for filetsv, it may be reasonable to support wildcard directories/names as input.

Policy skipping

It may be reasonable to skip any external policies that are already loaded/defined by the Perl::Critic profile. Presumably those represent overlaps and should not be emitted twice.

BUGS

None known.