mirror of
https://github.com/github/codeql.git
synced 2026-04-11 18:14:01 +02:00
116 lines
3.8 KiB
Plaintext
116 lines
3.8 KiB
Plaintext
/**
|
|
* Provides classes and predicates for computing metrics on Java methods and constructors.
|
|
*/
|
|
overlay[local?]
|
|
module;
|
|
|
|
import semmle.code.java.Member
|
|
|
|
/** This class provides access to metrics information for callables. */
|
|
class MetricCallable extends Callable {
|
|
/**
|
|
* Gets a callable on which this callable depends.
|
|
*
|
|
* A callable `m` depends on another callable `n`
|
|
* if there exists a call to `n` from within `m`,
|
|
* taking overriding into account.
|
|
*/
|
|
MetricCallable getADependency() { this.polyCalls(result) }
|
|
|
|
/**
|
|
* The afferent coupling of a callable is defined as
|
|
* the number of callables that depend on this callable.
|
|
*
|
|
* This may also be referred to as the "fan-in" or
|
|
* "incoming dependencies" of a callable.
|
|
*/
|
|
int getAfferentCoupling() { result = count(MetricCallable m | m.getADependency() = this) }
|
|
|
|
/**
|
|
* The efferent coupling of a callable is defined as
|
|
* the number of callables on which this callable depends.
|
|
*
|
|
* This may also be referred to as the "fan-out" or
|
|
* "outgoing dependencies" of a callable.
|
|
*/
|
|
int getEfferentCoupling() { result = count(MetricCallable m | this.getADependency() = m) }
|
|
|
|
/**
|
|
* The cyclomatic complexity of a callable is defined as the number
|
|
* of branching statements (`if`, `while`, `do`, `for`, `switch`, `case`, `catch`)
|
|
* plus the number of branching expressions (`?`, `&&` and `||`)
|
|
* plus one.
|
|
*/
|
|
int getCyclomaticComplexity() {
|
|
result =
|
|
count(Stmt stmt | branchingStmt(stmt) and stmt.getEnclosingCallable() = this) +
|
|
count(Expr expr | branchingExpr(expr) and expr.getEnclosingCallable() = this) + 1
|
|
}
|
|
|
|
/**
|
|
* The Halstead length of a callable is estimated as the sum of the number of statements
|
|
* and expressions within the callable, plus one for the callable itself.
|
|
*/
|
|
int getHalsteadLength() {
|
|
result =
|
|
count(Stmt s | s.getEnclosingCallable() = this) +
|
|
count(Expr e | e.getEnclosingCallable() = this) + 1
|
|
}
|
|
|
|
/**
|
|
* The Halstead vocabulary of a callable is estimated as the number of unique Halstead IDs
|
|
* of all statements and expressions within the callable.
|
|
*/
|
|
int getHalsteadVocabulary() {
|
|
result =
|
|
count(string id |
|
|
exists(Stmt s | s.getEnclosingCallable() = this and id = s.getHalsteadID())
|
|
or
|
|
exists(Expr e | e.getEnclosingCallable() = this and id = e.getHalsteadID())
|
|
)
|
|
}
|
|
}
|
|
|
|
private predicate fallthroughSwitchCase(SwitchCase sc1, SwitchCase sc2) {
|
|
exists(SwitchStmt switch, int n | switch.getStmt(n) = sc1 and switch.getStmt(n + 1) = sc2)
|
|
or
|
|
exists(SwitchExpr switch, int n | switch.getStmt(n) = sc1 and switch.getStmt(n + 1) = sc2)
|
|
}
|
|
|
|
// Branching points in the sense of cyclomatic complexity are binary,
|
|
// so there should be a branching point for each non-default switch
|
|
// case (ignoring those that just fall through to the next case).
|
|
private predicate branchingSwitchCase(ConstCase sc) {
|
|
if sc.isRule()
|
|
then any()
|
|
else (
|
|
not fallthroughSwitchCase(sc, _) and
|
|
not defaultFallThrough(sc)
|
|
)
|
|
}
|
|
|
|
private predicate defaultFallThrough(ConstCase sc) {
|
|
exists(DefaultCase default | fallthroughSwitchCase(default, sc))
|
|
or
|
|
exists(ConstCase mid | defaultFallThrough(mid) and fallthroughSwitchCase(mid, sc))
|
|
}
|
|
|
|
/** Holds if `stmt` is a branching statement used for the computation of cyclomatic complexity. */
|
|
private predicate branchingStmt(Stmt stmt) {
|
|
stmt instanceof IfStmt or
|
|
stmt instanceof WhileStmt or
|
|
stmt instanceof DoStmt or
|
|
stmt instanceof ForStmt or
|
|
stmt instanceof EnhancedForStmt or
|
|
stmt instanceof PatternCase or
|
|
branchingSwitchCase(stmt) or
|
|
stmt instanceof CatchClause
|
|
}
|
|
|
|
/** Holds if `expr` is a branching expression used for the computation of cyclomatic complexity. */
|
|
private predicate branchingExpr(Expr expr) {
|
|
expr instanceof ConditionalExpr or
|
|
expr instanceof AndLogicalExpr or
|
|
expr instanceof OrLogicalExpr
|
|
}
|