Skip to content

Reefwing-Software/JSF-Lint

Repository files navigation

license release open source

JSF Linter for Embedded AI

A configurable C++ linter based on simplified JSF AV C++ Coding Standards (Lockheed Martin, 2005), adapted for embedded AI and edge deployment contexts.

Overview

The linter consists of two files:

File Purpose
jsf_lint.py Python linter engine (all rule checkers)
linter_rules.yaml Configurable rule definitions (enable/disable, severity, thresholds)

A CLAUDE.md file is included to instruct Claude Code on the active coding standards.

Requirements

  • Python 3.9+
  • PyYAML (pip install pyyaml)

Quick Start

# Lint a single file
python jsf_lint.py examples/sensor_filter.h

# Lint an entire project
python jsf_lint.py examples/

# JSON output for tooling
python jsf_lint.py src/ --format json

# GitHub Actions annotations
python jsf_lint.py src/ --format github --error-exit

Integrating with Claude Code

Option A: Project-Level CLAUDE.md (Recommended)

Copy CLAUDE.md and the linter files into your project root:

embedded-ai-book/
    CLAUDE.md              <-- Claude Code reads this automatically
    jsf_lint.py
    linter_rules.yaml
    src/
        chapter_03/
            sensor_filter.h
            sensor_filter.cpp
        chapter_07/
            pid_controller.h
            pid_controller.cpp

Claude Code reads CLAUDE.md at the start of every session and will apply the coding standards when writing or reviewing code.

Option B: Claude Code Custom Slash Command

Create a .claude/commands/lint.md file in your project:

---
description: Run JSF AV linter on project code
---

Run the JSF linter on the specified files or directories.
Use `python jsf_lint.py <target>` from the project root.
Report all violations grouped by severity.
For each error-level violation, suggest a concrete fix.

Then invoke it in Claude Code with:

/lint src/chapter_03/

Option C: Pre-Commit Hook

Add a .pre-commit-config.yaml entry or a git hook script:

#!/bin/bash
# .git/hooks/pre-commit
python jsf_lint.py src/ --error-exit

Configuring Rules

All rules live in linter_rules.yaml. The structure is:

category_name:
  rule_name:
    enabled: true          # Toggle on/off
    severity: error        # error | warning | info
    jsf_ref: "AV Rule N"  # Traceability to original standard
    description: "..."     # Human-readable explanation
    params:                # Rule-specific thresholds
      max_lines: 100
    pattern: "\\bgoto\\b"  # Regex for pattern-based rules
    patterns:              # Multiple regex patterns
      - "\\bthrow\\b"
      - "\\bcatch\\b"

Common Customisations

Relax function length for complex inference pipelines:

max_function_length:
  params:
    max_lines: 150

Allow printf for debug builds (already disabled by default):

no_stdio:
  enabled: false

Tighten line length for book formatting:

max_line_length:
  params:
    max_chars: 80

Add values to the magic number whitelist:

no_magic_numbers:
  params:
    allowed_values: [0, 1, 2, -1, 255, 1024]

Inline Suppressions

Suppress a specific rule on a single line by appending a comment:

int legacy_val = 42; // NOLINT(no_magic_numbers)

The suppression marker is configurable in linter_rules.yaml under the suppressions section.

Rules Summary

The table below lists all implemented rules and their default state.

Complexity

Rule JSF Ref Default Severity
max_function_length AV Rule 1 100 lines warning
max_function_args AV Rule 110 6 args warning
max_line_length AV Rule 41 100 chars info

Prohibited Features

Rule JSF Ref Default Severity
no_goto AV Rule 189 enabled error
no_continue AV Rule 190 enabled error
no_exceptions AV Rule 208 enabled error
no_unions AV Rule 153 enabled error
no_errno AV Rule 17 enabled warning
no_setjmp_longjmp AV Rule 20 enabled error
no_signal_h AV Rule 21 enabled error
no_stdio AV Rule 22 disabled warning
no_atoi_atof AV Rule 23 enabled warning
no_abort_exit AV Rule 24 enabled error
no_register AV Rule 140 enabled info

Type Safety

Rule JSF Ref Default Severity
no_raw_int_types AV Rule 209 enabled warning
no_c_style_casts AV Rule 185 enabled error
no_octal_constants AV Rule 149 enabled error
hex_uppercase AV Rule 150 enabled info
literal_suffix_upper AV Rule 14 enabled info

Memory Safety

Rule JSF Ref Default Severity
no_malloc_free AV Rule 206 enabled error
no_raw_new_delete AV Rule 206 enabled warning
volatile_for_hw_only AV Rule 205 enabled warning

Control Flow

Rule JSF Ref Default Severity
braces_required AV Rule 59 enabled error
switch_default AV Rule 194 enabled warning
no_float_loop_counter AV Rule 197 enabled error
single_return AV Rule 113 disabled info

Style

Rule JSF Ref Default Severity
no_tabs AV Rule 43 enabled info
no_magic_numbers AV Rule 151 enabled warning
one_decl_per_line AV Rule 152 enabled warning
no_commented_out_code AV Rule 127 enabled warning
include_guard AV Rule 27 enabled error
cpp_comments_only AV Rule 126 enabled info

Classes

Rule JSF Ref Default Severity
virtual_destructor AV Rule 78 enabled error
explicit_constructors AV Rule 177 enabled warning
no_public_data_class AV Rule 67 enabled warning

Embedded / Safety

Rule JSF Ref Default Severity
define_only_for_guards AV Rule 29-31 enabled warning

Extending the Linter

To add a new rule:

  1. Add the rule definition to linter_rules.yaml under the appropriate category.
  2. If it is pattern-based, just add a pattern: or patterns: field. The existing PatternChecker will handle it.
  3. If it requires custom logic, create a new RuleChecker subclass in jsf_lint.py and register it in JSFLinter.CHECKER_MAP.
  4. Test with a sample file containing both violations and clean code.

Running Tests

The test suite uses Python's built-in unittest module and has no additional dependencies beyond PyYAML. From the repository root:

python tests/test_checkers.py

For more detailed output with pytest (optional):

pip install pytest
python -m pytest tests/test_checkers.py -v

The suite contains 69 tests across eight areas:

Test Class What It Verifies
TestCleanFixture A well-written file produces zero violations
TestAllErrorsFixture Every rule fires the exact expected number of times
TestSuppressionFixture NOLINT comments suppress their target rules
TestSeverityClassification Error, warning, and info severity are assigned correctly
TestOutputFormats Text, JSON, and GitHub annotation output all parse correctly
TestErrorExitCode --error-exit returns code 1 on errors, 0 on clean files
TestRuleToggle Disabling a rule in YAML stops it from firing
TestPathExclusion Excluded directories produce no violations
TestFalsePositiveImmunity Keywords in strings and comments do not trigger rules
TestJSFTraceability Every violation carries a valid JSF AV Rule reference

When adding or modifying rules, update the EXPECTED_COUNTS dictionary in TestAllErrorsFixture and the corresponding line in tests/fixtures/all_errors.cpp to keep the tests in sync.

Limitations

This is a regex-based linter, not a full AST parser. It will not catch:

  • Recursion (requires call graph analysis)
  • Cross-file violations (single-file scope)
  • Template instantiation issues
  • Semantic type narrowing

The C-style cast checker intentionally exempts (void) casts, which are a standard idiom for suppressing unused-variable warnings in embedded C++.

For production safety-critical work, pair this linter with clang-tidy, MISRA checkers, or Polyspace. This tool is designed for rapid feedback during example development.

License

The JSF AV C++ Coding Standards document is approved for public release by Lockheed Martin (Distribution Statement A). This linter implementation is provided under the MIT License.

About

A configurable C++ linter based on simplified JSF AV C++ Coding Standards

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages