Software metrics turn selected program structures into numbers. Their value is
not that a number can replace design judgment; it is that a precisely defined
number makes two structural snapshots comparable. This chapter develops the
theory behind libcpg's CK, LCOM, Halstead, cyclomatic, cognitive, and
maintainability metrics and explains why resolved graph evidence matters.
The implemented metrics observe three distinct scales:
| Scale | Question | Evidence |
|---|---|---|
| Method | How many structured decisions and nesting burdens occur? | Function AST/CFG semantics and resolved self-calls. |
| Class | Do methods share state, invoke one another, inherit, or call other types? | Nominal ownership, field DFG/reference edges, inheritance, and resolved calls. |
| Composite | How do volume, path count, line span, and comments combine into one comparative index? | Halstead counts, cyclomatic complexity, source ranges, and comment nodes. |
Keeping the scales separate prevents a common category error. LCOM does not measure method control-flow complexity; cyclomatic complexity does not measure whether a class has one responsibility; and the maintainability index does not prove how long a future change will take.
Suppose two methods contain the text x. Text alone cannot establish that they
share state: one x might be a local, an unrelated receiver's field, or a field
of another same-named class. The right abstraction is an incidence relation
between declarations.
Let
An incidence FieldRead/FieldWrite; the second is a
Reference to the declaration. This retained witness distinguishes a real
method-field topology from a name-matching approximation.
Figure 1 — evidence is resolved before it is counted. Source:
code-metrics-pipeline.puml.
Chidamber and Kemerer proposed six object-oriented measures in their 1991
conference paper and 1994 journal treatment. libcpg implements five class
fields directly and expands the sixth, lack of cohesion, into LCOM1–5.
Weighted Methods per Class (WMC) is a sum, not necessarily a method count. If
libcpg selects McCabe cyclomatic complexity as
Treat child -> parent inheritance edges as a directed graph. Depth of
Inheritance Tree (DIT) is the longest parent path from a class to a root;
Number of Children (NOC) is immediate reverse degree. Real or malformed input
can contain an inheritance cycle, for which an unrestricted longest walk is
undefined. libcpg first condenses every strongly connected component (SCC),
then computes longest paths on the resulting directed acyclic graph. Every
member of one cyclic SCC receives the same finite depth.
Coupling Between Object classes (CBO) is a distinct-neighbor count. The implemented static evidence is symmetric: a resolved incoming/outgoing call or a CPG type edge couples the two nominal owners. Duplicate calls do not increase CBO.
Response For a Class (RFC) is instead a set of callable functions:
Only direct resolved callees are included. A transitive call closure would measure a different, potentially much larger property and would make RFC depend on arbitrary search depth. The call graph can improve without changing this definition: each newly resolved call supplies one more real edge to consider.
“LCOM” has referred to several incompatible formulae. A report must name the
variant. Let
LCOM1 counts unordered method pairs with disjoint field sets. LCOM2 subtracts the number of sharing pairs and floors at zero. Their scale grows with the number of methods, which makes raw values unsuitable for comparing differently sized classes without context.
Li and Henry recast cohesion as connected sets of methods; Hitz and Montazeri gave the graph-theoretic form and added internal calls. With one method per vertex:
- LCOM3 counts connected components formed by shared-field edges;
- LCOM4 counts components after resolved internal call edges are added.
This distinction handles an accessor-mediated design. If method report
calls get_x and only get_x directly reads x, LCOM3 keeps them separate;
LCOM4 joins them through the call. Neither result is universally “better”—they
answer different evidence questions.
Henderson-Sellers LCOM5 normalizes average field use. For
The extreme values have useful interpretations:
- if every method touches every field, average usage is
$m$ and LCOM5 is zero; - if every field is touched by exactly one method, average usage is one and LCOM5 is one.
Classes with fewer than two methods or no fields make the denominator or field
average degenerate. libcpg defines their LCOM5 as zero and exposes the method
and field vectors so the caller can recognize the degenerate case.
McCabe defined cyclomatic complexity from control-flow topology. For a connected
control-flow graph with
For structured control constructs, the equivalent practical form is one plus
the number of decisions. libcpg uses that form over normalized CPG kinds so a
function with no decisions remains one. Short-circuit Boolean operations are
decisions because one operand can prevent evaluation of the next.
Cyclomatic complexity treats a top-level if and an if nested inside three
loops as one decision each. Cognitive complexity distinguishes them. A
structure at nesting depth libcpg publishes the exact subset of normalized constructs it
counts so the result can be reproduced.
Halstead partitions a program representation into operators and operands. Four primitive counts determine the implemented derived measures:
| Symbol | Definition |
|---|---|
| distinct operators | |
| distinct operands | |
| total operator occurrences | |
| total operand occurrences |
Vocabulary is
The formulas do not determine how a language is tokenized. libcpg deliberately
uses semantic CPG categories: an If is an operator, an identifier spelling is
an operand, and discarded delimiters do not exist. This gives one common
cross-language measurement vocabulary while making the evidence independent of
retained source. It also means the result should not be equated with a
token-level tool unless both classifiers are aligned first.
Oman and Hagemeister proposed combining existing measures into a maintainability
index; Coleman and colleagues later described its practical use. The
pgmcp-compatible variant combines Halstead volume
libcpg floors logarithm inputs at one and clamps the raw result to
$[0,100]. The comment term is not monotone over every mathematically possible
ratio because it contains a sine; normal source inputs keep
A metric is exact relative to its definition and input evidence. That does not make its quality interpretation exact.
The implemented computations can establish statements such as “three resolved
methods form two field-sharing components” or “this semantic vocabulary has
volume
The safest workflow retains an evidence chain:
source + frontend policy
-> CPG node/edge snapshot
-> resolver and DFG configuration
-> metric options and scalar report
-> human interpretation in project context
See the component contract, the design decision, and the validation ledger.
- McCabe, T. J. (1976). A Complexity Measure. DOI: 10.1109/TSE.1976.233837.
- Chidamber, S. R., and Kemerer, C. F. (1991). Towards a Metrics Suite for Object Oriented Design. DOI: 10.1145/117954.117970.
- Chidamber, S. R., and Kemerer, C. F. (1994). A Metrics Suite for Object Oriented Design. DOI: 10.1109/32.295895.
- Li, W., and Henry, S. (1993). Object-Oriented Metrics that Predict Maintainability. DOI: 10.1016/0164-1212(93)90077-B.
- Hitz, M., and Montazeri, B. (1995). Measuring Coupling and Cohesion in Object-Oriented Systems. Author-hosted paper. No DOI was assigned.
- Henderson-Sellers, B. (1996). Object-Oriented Metrics: Measures of Complexity. Prentice Hall PTR. ISBN 0-13-239872-9. No DOI was assigned.
- Halstead, M. H. (1977). Elements of Software Science. Elsevier/North-Holland. ISBN 0-444-00205-7. No DOI was assigned.
- Campbell, G. A. (2018). Cognitive Complexity: An Overview and Evaluation. DOI: 10.1145/3194164.3194186.
- Oman, P., and Hagemeister, J. (1992). Metrics for Assessing a Software System's Maintainability. DOI: 10.1109/ICSM.1992.242525.
- Coleman, D., Ash, D., Lowther, B., and Oman, P. (1994). Using Metrics to Evaluate Software System Maintainability. DOI: 10.1109/2.303623.