mirror of
https://github.com/github/codeql.git
synced 2026-01-14 06:54:48 +01:00
69 lines
2.3 KiB
Plaintext
69 lines
2.3 KiB
Plaintext
/**
|
|
* @name Missing 'this' qualifier
|
|
* @description Referencing an undeclared global variable in a class that has a member of the same name is confusing and may indicate a bug.
|
|
* @kind problem
|
|
* @problem.severity error
|
|
* @id js/missing-this-qualifier
|
|
* @tags maintainability
|
|
* correctness
|
|
* methods
|
|
* @precision high
|
|
*/
|
|
|
|
import javascript
|
|
|
|
/**
|
|
* Holds if `call` is a call to global function `gv` which has the same name as method
|
|
* `intendedTarget` in the same class as `call`.
|
|
*/
|
|
predicate maybeMissingThis(CallExpr call, MethodDeclaration intendedTarget, GlobalVariable gv) {
|
|
call.getCallee() = gv.getAnAccess() and
|
|
call.getCalleeName() = intendedTarget.getName() and
|
|
exists(MethodDefinition caller |
|
|
caller.getBody() = getRelevantCallExprContainer(call) and
|
|
intendedTarget.getDeclaringClass() = caller.getDeclaringClass()
|
|
)
|
|
}
|
|
|
|
pragma[noinline]
|
|
private StmtContainer getRelevantCallExprContainer(CallExpr c) {
|
|
result = c.getContainer() and
|
|
c.getCallee() = any(GlobalVariable v).getAnAccess()
|
|
}
|
|
|
|
from CallExpr call, MethodDeclaration intendedTarget, GlobalVariable gv
|
|
where
|
|
maybeMissingThis(call, intendedTarget, gv) and
|
|
// exceptions:
|
|
not (
|
|
// affected by `with`
|
|
exists(WithStmt with | with.mayAffect(call.getCallee()))
|
|
or
|
|
// locally declared, so probably intentional
|
|
gv.getADeclaration().getTopLevel() = call.getTopLevel()
|
|
or
|
|
// linter declaration for the variable
|
|
exists(Linting::GlobalDeclaration glob | glob.declaresGlobalForAccess(call.getCallee()))
|
|
or
|
|
// externs declaration for the variable
|
|
exists(ExternalGlobalDecl egd | egd.getName() = call.getCalleeName())
|
|
or
|
|
// variable available through a namespace
|
|
exists(Variable decl |
|
|
decl.getName() = gv.getName() and
|
|
decl.isNamespaceExport() and
|
|
getRelevantCallExprContainer(call).getEnclosingContainer*() instanceof NamespaceDeclaration
|
|
)
|
|
or
|
|
// call to global function with additional arguments
|
|
exists(Function self |
|
|
intendedTarget.getBody() = self and
|
|
call.getEnclosingFunction() = self and
|
|
call.flow().(DataFlow::CallNode).getNumArgument() > self.getNumParameter() and
|
|
not self.hasRestParameter() and
|
|
not self.usesArgumentsObject()
|
|
)
|
|
)
|
|
select call, "This call refers to a global function, and not the local method $@.", intendedTarget,
|
|
intendedTarget.getName()
|