halstead

package
v1.0.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 13, 2026 License: Apache-2.0, Apache-2.0 Imports: 21 Imported by: 0

README

Halstead Complexity Analysis

Preface

Halstead metrics attempt to measure the "volume" and "difficulty" of a program based on the number of operators and operands, treating code like a piece of literature.

Problem

How do we compare the complexity of two different programs? Simple LOC (Lines of Code) is misleading. We need a metric that accounts for the density of logic.

How analyzer solves it

The Halstead analyzer computes a suite of metrics:

  • Program Length (N): Total number of operators + operands.
  • Vocabulary (n): Unique operators + unique operands.
  • Volume (V): Information content of the program.
  • Difficulty (D): How hard it is to write or understand.
  • Effort (E): Mental effort required.

Historical context

Proposed by Maurice Halstead in 1977 in his book "Elements of Software Science". It was one of the first attempts to apply scientific measurement to software.

Real world examples

  • Algorithmic Complexity: Comparing different implementations of the same algorithm.
  • Code Quality Baselines: Establishing a baseline for "acceptable" module volume.

How analyzer works here

  1. UAST Traversal: Scans the Abstract Syntax Tree.
  2. Token Classification: Identifies tokens as either Operators (arithmetic, logical, assignments, function calls) or Operands (variables, constants, strings).
  3. Calculation: Applies Halstead's formulas to the counts.

Limitations

  • Modern Relevance: Developed for Algol/Fortran. Some argue it's less relevant for modern, high-level, expressive languages, but it still provides a useful relative comparison.

Further plans

  • Calibrating coefficients for modern languages.

Documentation

Overview

Package halstead provides halstead functionality.

Index

Constants

View Source
const (
	// TimeConstant is the standard constant used in time-to-program estimation (18 seconds).
	TimeConstant = 18.0
	// BugConstant is the standard constant used in delivered bugs estimation.
	BugConstant = 3000.0
	// DifficultyDivisor is used in the difficulty formula: n1/2 * (N2/n2).
	DifficultyDivisor = 2.0
)

Halstead formula constants.

View Source
const (
	VolumeThresholdLow    = 100
	VolumeThresholdMedium = 1000
	VolumeThresholdHigh   = 5000
)

Volume thresholds for complexity classification.

View Source
const (
	SectionTitle = "HALSTEAD"

	// ScoreExcellentMax is the maximum difficulty for an excellent Halstead score.
	ScoreExcellentMax = 5.0
	ScoreGoodMax      = 15.0
	ScoreFairMax      = 30.0

	ScoreExcellent = 1.0
	ScoreGood      = 0.8
	ScoreFair      = 0.6
	ScorePoor      = 0.3

	// MetricTotalFunctions is the label for the total functions metric.
	MetricTotalFunctions = "Total Functions"
	MetricDistinctOps    = "Distinct Operators (n1)"
	MetricDistinctOpnds  = "Distinct Operands (n2)"
	MetricTotalOps       = "Total Operators (N1)"
	MetricTotalOpnds     = "Total Operands (N2)"
	MetricVocabulary     = "Vocabulary"
	MetricVolume         = "Volume"
	MetricDifficulty     = "Difficulty"
	MetricEffort         = "Effort"
	MetricEstBugs        = "Est. Bugs"

	// DistLowMax is the maximum volume for the "low" distribution bucket.
	DistLowMax     = 100
	DistMedMax     = 1000
	DistHighMax    = 5000
	DistLabelLow   = "Low (<=100)"
	DistLabelMed   = "Medium (101-1000)"
	DistLabelHigh  = "High (1001-5000)"
	DistLabelVHigh = "Very High (>5000)"

	// IssueSeverityFairMin is the minimum effort value for fair severity.
	IssueSeverityFairMin = 10000.0
	IssueSeverityPoorMin = 50000.0
	IssueValuePrefix     = "effort="

	// KeyTotalFunctions is the report key for the total number of functions.
	KeyTotalFunctions = "total_functions"
	KeyVocabulary     = "vocabulary"
	KeyVolume         = "volume"
	KeyDifficulty     = "difficulty"
	KeyEffort         = "effort"
	KeyDeliveredBugs  = "delivered_bugs"
	KeyMessage        = "message"
	KeyFunctions      = "functions"
	KeyFuncName       = "name"
	KeyFuncEffort     = "effort"
	KeyFuncVolume     = "volume"
	KeyFuncBugs       = "delivered_bugs"

	// DefaultStatusMessage is the fallback message when no Halstead data is available.
	DefaultStatusMessage = "No Halstead data available"
)

Section rendering constants.

View Source
const (
	// MaxDepthValue is the default maximum UAST traversal depth for Halstead analysis.
	MaxDepthValue = 10
)

Configuration constants for Halstead analysis.

View Source
const (
	// MaxItemsValue is the maximum number of items displayed in Halstead report summaries.
	MaxItemsValue = 10
)

Configuration constants for Halstead report formatting.

Variables

View Source
var ErrInvalidFunctionsData = errors.New("invalid halstead report: expected []map[string]any for functions")

ErrInvalidFunctionsData indicates the report doesn't contain expected functions data.

Functions

func RegisterPlotSections

func RegisterPlotSections()

RegisterPlotSections registers the halstead plot section renderer with the analyze package.

Types

type AggregateData

type AggregateData struct {
	TotalFunctions    int     `json:"total_functions"    yaml:"total_functions"`
	Volume            float64 `json:"volume"             yaml:"volume"`
	Difficulty        float64 `json:"difficulty"         yaml:"difficulty"`
	Effort            float64 `json:"effort"             yaml:"effort"`
	TimeToProgram     float64 `json:"time_to_program"    yaml:"time_to_program"`
	DeliveredBugs     float64 `json:"delivered_bugs"     yaml:"delivered_bugs"`
	DistinctOperators int     `json:"distinct_operators" yaml:"distinct_operators"`
	DistinctOperands  int     `json:"distinct_operands"  yaml:"distinct_operands"`
	TotalOperators    int     `json:"total_operators"    yaml:"total_operators"`
	TotalOperands     int     `json:"total_operands"     yaml:"total_operands"`
	Vocabulary        int     `json:"vocabulary"         yaml:"vocabulary"`
	Length            int     `json:"length"             yaml:"length"`
	EstimatedLength   float64 `json:"estimated_length"   yaml:"estimated_length"`
	HealthScore       float64 `json:"health_score"       yaml:"health_score"`
	Message           string  `json:"message"            yaml:"message"`
}

AggregateData contains summary statistics.

type AggregateMetric

type AggregateMetric struct {
	metrics.MetricMeta
}

AggregateMetric computes summary statistics.

func NewAggregateMetric

func NewAggregateMetric() *AggregateMetric

NewAggregateMetric creates the aggregate metric.

func (*AggregateMetric) Compute

func (m *AggregateMetric) Compute(input *ReportData) AggregateData

Compute calculates aggregate statistics.

type Aggregator

type Aggregator struct {
	*common.Aggregator
	common.PerFileRetainer
	// contains filtered or unexported fields
}

Aggregator aggregates Halstead analysis results.

func NewAggregator

func NewAggregator() *Aggregator

NewAggregator creates a new Halstead aggregator.

func (*Aggregator) Aggregate

func (ha *Aggregator) Aggregate(results map[string]analyze.Report)

Aggregate overrides the base Aggregate method to collect detailed functions.

func (*Aggregator) GetResult

func (ha *Aggregator) GetResult() analyze.Report

GetResult overrides the base GetResult method to include detailed functions.

func (*Aggregator) SetAggregationMode

func (ha *Aggregator) SetAggregationMode(mode analyze.AggregationMode)

SetAggregationMode propagates the mode to both the base aggregator and the detailed data collector.

type Analyzer

type Analyzer struct {
	// contains filtered or unexported fields
}

Analyzer provides Halstead complexity measures analysis.

func NewAnalyzer

func NewAnalyzer() *Analyzer

NewAnalyzer creates a new Analyzer with common modules.

func (*Analyzer) Analyze

func (h *Analyzer) Analyze(root *node.Node) (analyze.Report, error)

Analyze performs Halstead analysis on the UAST.

func (*Analyzer) Configure

func (h *Analyzer) Configure(_ map[string]any) error

Configure configures the analyzer.

func (*Analyzer) CreateAggregator

func (h *Analyzer) CreateAggregator() analyze.ResultAggregator

CreateAggregator returns a new aggregator for Halstead analysis.

func (*Analyzer) CreateReportSection

func (h *Analyzer) CreateReportSection(report analyze.Report) analyze.ReportSection

CreateReportSection creates a ReportSection from report data.

func (*Analyzer) CreateVisitor

func (h *Analyzer) CreateVisitor() analyze.AnalysisVisitor

CreateVisitor creates a new visitor for Halstead analysis.

func (*Analyzer) Description

func (h *Analyzer) Description() string

Description returns the analyzer description.

func (*Analyzer) Descriptor

func (h *Analyzer) Descriptor() analyze.Descriptor

Descriptor returns stable analyzer metadata.

func (*Analyzer) Flag

func (h *Analyzer) Flag() string

Flag returns the CLI flag for the analyzer.

func (*Analyzer) FormatReport

func (h *Analyzer) FormatReport(report analyze.Report, w io.Writer) error

FormatReport formats the analysis report for display.

func (*Analyzer) FormatReportBinary

func (h *Analyzer) FormatReportBinary(report analyze.Report, w io.Writer) error

FormatReportBinary formats the analysis report as binary envelope.

func (*Analyzer) FormatReportJSON

func (h *Analyzer) FormatReportJSON(report analyze.Report, w io.Writer) error

FormatReportJSON formats the analysis report as JSON.

func (*Analyzer) FormatReportPlot

func (h *Analyzer) FormatReportPlot(report analyze.Report, w io.Writer) error

FormatReportPlot generates an HTML plot visualization for Halstead analysis.

func (*Analyzer) FormatReportYAML

func (h *Analyzer) FormatReportYAML(report analyze.Report, w io.Writer) error

FormatReportYAML formats the analysis report as YAML.

func (*Analyzer) ListConfigurationOptions

func (h *Analyzer) ListConfigurationOptions() []pipeline.ConfigurationOption

ListConfigurationOptions returns the configuration options for the analyzer.

func (*Analyzer) Name

func (h *Analyzer) Name() string

Name returns the analyzer name.

func (*Analyzer) Thresholds

func (h *Analyzer) Thresholds() analyze.Thresholds

Thresholds returns the color-coded thresholds for Halstead metrics.

type ComputedMetrics

type ComputedMetrics struct {
	FunctionHalstead    []FunctionHalsteadData   `json:"function_halstead"     yaml:"function_halstead"`
	Distribution        EffortDistributionData   `json:"distribution"          yaml:"distribution"`
	HighEffortFunctions []HighEffortFunctionData `json:"high_effort_functions" yaml:"high_effort_functions"`
	Aggregate           AggregateData            `json:"aggregate"             yaml:"aggregate"`
}

ComputedMetrics holds all computed metric results for the Halstead analyzer.

func ComputeAllMetrics

func ComputeAllMetrics(report analyze.Report) (*ComputedMetrics, error)

ComputeAllMetrics runs all Halstead metrics and returns the results.

func (*ComputedMetrics) AnalyzerName

func (m *ComputedMetrics) AnalyzerName() string

AnalyzerName returns the name of the analyzer that produced these metrics.

func (*ComputedMetrics) ToJSON

func (m *ComputedMetrics) ToJSON() any

ToJSON returns the metrics in a format suitable for JSON marshaling.

func (*ComputedMetrics) ToYAML

func (m *ComputedMetrics) ToYAML() any

ToYAML returns the metrics in a format suitable for YAML marshaling.

type Config

type Config struct {
	// IncludeFunctionBreakdown determines whether to include per-function metrics.
	IncludeFunctionBreakdown bool
	// IncludeTimeEstimate determines whether to calculate time to program estimates.
	IncludeTimeEstimate bool
	// IncludeBugEstimate determines whether to calculate delivered bug estimates.
	IncludeBugEstimate bool
}

Config holds configuration for Halstead analysis.

type EffortDistributionData

type EffortDistributionData struct {
	Low      int `json:"low"       yaml:"low"`
	Medium   int `json:"medium"    yaml:"medium"`
	High     int `json:"high"      yaml:"high"`
	VeryHigh int `json:"very_high" yaml:"very_high"`
}

EffortDistributionData contains effort distribution counts.

type EffortDistributionMetric

type EffortDistributionMetric struct {
	metrics.MetricMeta
}

EffortDistributionMetric computes effort distribution.

func NewEffortDistributionMetric

func NewEffortDistributionMetric() *EffortDistributionMetric

NewEffortDistributionMetric creates the distribution metric.

func (*EffortDistributionMetric) Compute

Compute calculates effort distribution.

type FunctionData

type FunctionData struct {
	Name              string
	SourceFile        string
	Language          string
	Directory         string
	Volume            float64
	Difficulty        float64
	Effort            float64
	TimeToProgram     float64
	DeliveredBugs     float64
	EstimatedLength   float64
	DistinctOperators int
	DistinctOperands  int
	TotalOperators    int
	TotalOperands     int
	Vocabulary        int
	Length            int
}

FunctionData holds Halstead data for a single function.

type FunctionHalsteadData

type FunctionHalsteadData struct {
	Name            string  `json:"name"                  yaml:"name"`
	SourceFile      string  `json:"source_file,omitempty" yaml:"source_file,omitempty"`
	Language        string  `json:"language,omitempty"    yaml:"language,omitempty"`
	Directory       string  `json:"directory,omitempty"   yaml:"directory,omitempty"`
	Volume          float64 `json:"volume"                yaml:"volume"`
	Difficulty      float64 `json:"difficulty"            yaml:"difficulty"`
	Effort          float64 `json:"effort"                yaml:"effort"`
	TimeToProgram   float64 `json:"time_to_program"       yaml:"time_to_program"`
	DeliveredBugs   float64 `json:"delivered_bugs"        yaml:"delivered_bugs"`
	ComplexityLevel string  `json:"complexity_level"      yaml:"complexity_level"`
}

FunctionHalsteadData contains Halstead metrics for a function.

type FunctionHalsteadMetric

type FunctionHalsteadMetric struct {
	metrics.MetricMeta
}

FunctionHalsteadMetric computes per-function Halstead data.

func NewFunctionHalsteadMetric

func NewFunctionHalsteadMetric() *FunctionHalsteadMetric

NewFunctionHalsteadMetric creates the function Halstead metric.

func (*FunctionHalsteadMetric) Compute

Compute calculates function Halstead data.

type FunctionHalsteadMetrics

type FunctionHalsteadMetrics struct {
	Operands                map[string]int `json:"operands"`
	Operators               map[string]int `json:"operators"`
	OperatorSketch          *cms.Sketch    `json:"-"                         yaml:"-"`
	OperandSketch           *cms.Sketch    `json:"-"                         yaml:"-"`
	Name                    string         `json:"name"`
	EstimatedTotalOperators int64          `json:"estimated_total_operators" yaml:"estimated_total_operators"`
	EstimatedTotalOperands  int64          `json:"estimated_total_operands"  yaml:"estimated_total_operands"`
	Length                  int            `json:"length"`
	TotalOperands           int            `json:"total_operands"`
	Vocabulary              int            `json:"vocabulary"`
	TotalOperators          int            `json:"total_operators"`
	EstimatedLength         float64        `json:"estimated_length"`
	Volume                  float64        `json:"volume"`
	Difficulty              float64        `json:"difficulty"`
	Effort                  float64        `json:"effort"`
	TimeToProgram           float64        `json:"time_to_program"`
	DeliveredBugs           float64        `json:"delivered_bugs"`
	DistinctOperands        int            `json:"distinct_operands"`
	DistinctOperators       int            `json:"distinct_operators"`
}

FunctionHalsteadMetrics contains Halstead metrics for a single function.

type FunctionReportItem

type FunctionReportItem struct {
	Operators               map[string]int
	Operands                map[string]int
	Name                    string
	VolumeAssessment        string
	DifficultyAssessment    string
	EffortAssessment        string
	EstimatedTotalOperators int64
	EstimatedTotalOperands  int64
	Length                  int
	TotalOperands           int
	Vocabulary              int
	TotalOperators          int
	DistinctOperands        int
	DistinctOperators       int
	EstimatedLength         float64
	Volume                  float64
	Difficulty              float64
	Effort                  float64
	TimeToProgram           float64
	DeliveredBugs           float64
}

FunctionReportItem is a typed representation of a per-function halstead report item. Includes assessment strings and operator/operand maps. Avoids map[string]any allocation.

type HighEffortFunctionData

type HighEffortFunctionData struct {
	Name          string  `json:"name"                  yaml:"name"`
	SourceFile    string  `json:"source_file,omitempty" yaml:"source_file,omitempty"`
	Language      string  `json:"language,omitempty"    yaml:"language,omitempty"`
	Directory     string  `json:"directory,omitempty"   yaml:"directory,omitempty"`
	Volume        float64 `json:"volume"                yaml:"volume"`
	Effort        float64 `json:"effort"                yaml:"effort"`
	TimeToProgram float64 `json:"time_to_program"       yaml:"time_to_program"`
	DeliveredBugs float64 `json:"delivered_bugs"        yaml:"delivered_bugs"`
	RiskLevel     string  `json:"risk_level"            yaml:"risk_level"`
}

HighEffortFunctionData identifies functions with high effort.

type HighEffortFunctionMetric

type HighEffortFunctionMetric struct {
	metrics.MetricMeta
}

HighEffortFunctionMetric identifies high-effort functions.

func NewHighEffortFunctionMetric

func NewHighEffortFunctionMetric() *HighEffortFunctionMetric

NewHighEffortFunctionMetric creates the high effort metric.

func (*HighEffortFunctionMetric) Compute

Compute identifies high effort functions.

type Metrics

type Metrics struct {
	Functions               []*FunctionHalsteadMetrics `json:"functions"`
	EstimatedLength         float64                    `json:"estimated_length"`
	EstimatedTotalOperators int64                      `json:"estimated_total_operators" yaml:"estimated_total_operators"`
	EstimatedTotalOperands  int64                      `json:"estimated_total_operands"  yaml:"estimated_total_operands"`
	TotalOperators          int                        `json:"total_operators"`
	TotalOperands           int                        `json:"total_operands"`
	Vocabulary              int                        `json:"vocabulary"`
	Length                  int                        `json:"length"`
	DistinctOperators       int                        `json:"distinct_operators"`
	Volume                  float64                    `json:"volume"`
	Difficulty              float64                    `json:"difficulty"`
	Effort                  float64                    `json:"effort"`
	TimeToProgram           float64                    `json:"time_to_program"`
	DeliveredBugs           float64                    `json:"delivered_bugs"`
	DistinctOperands        int                        `json:"distinct_operands"`
}

Metrics holds all Halstead complexity measures.

type MetricsCalculator

type MetricsCalculator struct{}

MetricsCalculator handles Halstead metrics calculations.

func NewMetricsCalculator

func NewMetricsCalculator() *MetricsCalculator

NewMetricsCalculator creates a new metrics calculator.

func (*MetricsCalculator) CalculateHalsteadMetrics

func (c *MetricsCalculator) CalculateHalsteadMetrics(metrics halsteadMetrics)

CalculateHalsteadMetrics calculates all derived Halstead metrics. Works with both Metrics and FunctionHalsteadMetrics types.

func (*MetricsCalculator) SumMap

func (c *MetricsCalculator) SumMap(intMap map[string]int) int

SumMap sums all values in an integer map.

type OperatorOperandDetector

type OperatorOperandDetector struct{}

OperatorOperandDetector handles detection of operators and operands in UAST nodes.

func NewOperatorOperandDetector

func NewOperatorOperandDetector() *OperatorOperandDetector

NewOperatorOperandDetector creates a new detector.

func (*OperatorOperandDetector) CollectOperatorsAndOperands

func (d *OperatorOperandDetector) CollectOperatorsAndOperands(
	nd *node.Node, operators, operands map[string]int,
)

CollectOperatorsAndOperands recursively collects operators and operands from a node.

func (*OperatorOperandDetector) GetOperandName

func (d *OperatorOperandDetector) GetOperandName(target *node.Node) node.Type

GetOperandName extracts the operand name from a node.

func (*OperatorOperandDetector) GetOperatorName

func (d *OperatorOperandDetector) GetOperatorName(target *node.Node) node.Type

GetOperatorName extracts the operator name from a node.

func (*OperatorOperandDetector) IsOperand

func (d *OperatorOperandDetector) IsOperand(target *node.Node) bool

IsOperand determines if a node represents an operand in Halstead complexity analysis.

func (*OperatorOperandDetector) IsOperator

func (d *OperatorOperandDetector) IsOperator(target *node.Node) bool

IsOperator determines if a node represents an operator in Halstead complexity analysis.

type ReportData

type ReportData struct {
	TotalFunctions    int
	Volume            float64
	Difficulty        float64
	Effort            float64
	TimeToProgram     float64
	DeliveredBugs     float64
	DistinctOperators int
	DistinctOperands  int
	TotalOperators    int
	TotalOperands     int
	Vocabulary        int
	Length            int
	EstimatedLength   float64
	Functions         []FunctionData
	Message           string
}

ReportData is the parsed input data for Halstead metrics computation.

func ParseReportData

func ParseReportData(report analyze.Report) (*ReportData, error)

ParseReportData extracts ReportData from an analyzer report.

type ReportFormatter

type ReportFormatter struct {
	// contains filtered or unexported fields
}

ReportFormatter handles formatting of Halstead analysis reports.

func NewReportFormatter

func NewReportFormatter() *ReportFormatter

NewReportFormatter creates a new report formatter.

func (*ReportFormatter) FormatReport

func (rf *ReportFormatter) FormatReport(report analyze.Report, w io.Writer) error

FormatReport formats the analysis report for display.

func (*ReportFormatter) FormatReportBinary

func (rf *ReportFormatter) FormatReportBinary(report analyze.Report, w io.Writer) error

FormatReportBinary formats the analysis report as binary envelope.

func (*ReportFormatter) FormatReportJSON

func (rf *ReportFormatter) FormatReportJSON(report analyze.Report, w io.Writer) error

FormatReportJSON formats the analysis report as JSON.

func (*ReportFormatter) FormatReportYAML

func (rf *ReportFormatter) FormatReportYAML(report analyze.Report, w io.Writer) error

FormatReportYAML formats the analysis report as YAML.

func (*ReportFormatter) GetBugAssessment

func (rf *ReportFormatter) GetBugAssessment(bugs float64) string

GetBugAssessment returns an assessment with emoji for delivered bugs.

func (*ReportFormatter) GetDifficultyAssessment

func (rf *ReportFormatter) GetDifficultyAssessment(difficulty float64) string

GetDifficultyAssessment returns an assessment with emoji for difficulty.

func (*ReportFormatter) GetEffortAssessment

func (rf *ReportFormatter) GetEffortAssessment(effort float64) string

GetEffortAssessment returns an assessment with emoji for effort.

func (*ReportFormatter) GetHalsteadMessage

func (rf *ReportFormatter) GetHalsteadMessage(volume, difficulty, effort float64) string

GetHalsteadMessage returns a message based on the Halstead metrics.

func (*ReportFormatter) GetVolumeAssessment

func (rf *ReportFormatter) GetVolumeAssessment(volume float64) string

GetVolumeAssessment returns an assessment with emoji for volume.

type ReportSection

type ReportSection struct {
	analyze.BaseReportSection
	// contains filtered or unexported fields
}

ReportSection implements analyze.ReportSection for Halstead analysis.

func NewReportSection

func NewReportSection(report analyze.Report) *ReportSection

NewReportSection creates a ReportSection from a Halstead report.

func (*ReportSection) AllIssues

func (s *ReportSection) AllIssues() []analyze.Issue

AllIssues returns all functions sorted by effort descending.

func (*ReportSection) Distribution

func (s *ReportSection) Distribution() []analyze.DistributionItem

Distribution returns volume distribution categories.

func (*ReportSection) KeyMetrics

func (s *ReportSection) KeyMetrics() []analyze.Metric

KeyMetrics returns the key metrics for the Halstead section.

func (*ReportSection) TopIssues

func (s *ReportSection) TopIssues(n int) []analyze.Issue

TopIssues returns the top N functions with highest effort.

type Visitor

type Visitor struct {
	// contains filtered or unexported fields
}

Visitor implements NodeVisitor for Halstead analysis.

func NewVisitor

func NewVisitor() *Visitor

NewVisitor creates a new Visitor.

func (*Visitor) GetReport

func (v *Visitor) GetReport() analyze.Report

GetReport returns the collected analysis report.

func (*Visitor) OnEnter

func (v *Visitor) OnEnter(n *node.Node, _ int)

OnEnter is called when entering a node during AST traversal.

func (*Visitor) OnExit

func (v *Visitor) OnExit(n *node.Node, _ int)

OnExit is called when exiting a node during AST traversal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL