mirror of
https://github.com/github/codeql.git
synced 2025-12-24 12:46:34 +01:00
105 lines
3.4 KiB
Plaintext
105 lines
3.4 KiB
Plaintext
/**
|
|
* @name Superfluous trailing arguments
|
|
* @description A function is invoked with extra trailing arguments that are ignored.
|
|
* @kind problem
|
|
* @problem.severity warning
|
|
* @id js/superfluous-trailing-arguments
|
|
* @tags maintainability
|
|
* correctness
|
|
* language-features
|
|
* external/cwe/cwe-685
|
|
* @precision very-high
|
|
*/
|
|
|
|
import javascript
|
|
|
|
/**
|
|
* Holds if `fn` expects a fixed number of arguments, that is,
|
|
* it neither uses `arguments` nor has a rest parameter.
|
|
*/
|
|
predicate isFixedArity(Function fn) {
|
|
not fn.usesArgumentsObject() and
|
|
not fn.hasRestParameter() and
|
|
not fn.(ExternalFunction).isVarArgs()
|
|
}
|
|
|
|
/**
|
|
* Gets the maximum arity of any function that may be invoked at
|
|
* call site `invk`.
|
|
*
|
|
* This is only defined if all potential callees have a fixed arity.
|
|
*/
|
|
int maxArity(DataFlow::InvokeNode invk) {
|
|
forall(Function callee | callee = invk.getACallee() | isFixedArity(callee)) and
|
|
result = max(invk.getACallee().getNumParameter())
|
|
}
|
|
|
|
/**
|
|
* A list of spurious arguments passed at a call site.
|
|
*
|
|
* The list is represented by its first element (that is,
|
|
* the first spurious argument), but `hasLocationInfo` is
|
|
* defined to cover all subsequent arguments as well.
|
|
*/
|
|
class SpuriousArguments extends Expr {
|
|
DataFlow::InvokeNode invk;
|
|
|
|
SpuriousArguments() {
|
|
this = invk.getArgument(maxArity(invk)).asExpr() and
|
|
not invk.isIncomplete() and
|
|
not invk.getAstNode() instanceof TaggedTemplateExpr
|
|
}
|
|
|
|
/**
|
|
* Gets the call site at which the spurious arguments are passed.
|
|
*/
|
|
DataFlow::InvokeNode getCall() { result = invk }
|
|
|
|
/**
|
|
* Gets the number of spurious arguments, that is, the number of
|
|
* actual arguments minus the maximum number of arguments
|
|
* expected by any potential callee.
|
|
*/
|
|
int getCount() {
|
|
result = count(int i | exists(invk.getArgument(i)) and i >= maxArity(this.getCall()))
|
|
}
|
|
|
|
/**
|
|
* Holds if this element is at the specified location.
|
|
* The location spans column `startcolumn` of line `startline` to
|
|
* column `endcolumn` of line `endline` in file `filepath`.
|
|
* For more information, see
|
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
*/
|
|
predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
|
exists(DataFlow::Node lastArg |
|
|
lastArg = max(DataFlow::Node arg, int i | arg = invk.getArgument(i) | arg order by i)
|
|
|
|
|
lastArg.hasLocationInfo(_, _, _, endline, endcolumn)
|
|
)
|
|
}
|
|
}
|
|
|
|
from SpuriousArguments args, Function f, string arguments
|
|
where
|
|
f = args.getCall().getACallee() and
|
|
(if args.getCount() = 1 then arguments = "argument" else arguments = "arguments") and
|
|
(
|
|
// exclude empty functions, they are probably commented out debug utilities ...
|
|
exists(f.getABodyStmt()) or
|
|
// ... but include: constructors, arrows and externals/ambients
|
|
f instanceof Constructor or // unlikely to be a debug utility
|
|
f instanceof ArrowFunctionExpr or // cannot be empty
|
|
f instanceof ExternalFunction or // always empty
|
|
f.isAmbient() // always empty
|
|
) and
|
|
not (
|
|
// exclude no-param functions that trivially throw exceptions, they are probably placeholders
|
|
f.getNumParameter() = 0 and
|
|
f.getBodyStmt(0) instanceof ThrowStmt
|
|
)
|
|
select args, "Superfluous " + arguments + " passed to $@.", f, f.describe()
|