CodeQL queries 1.25
Skip to end of metadata
Go to start of metadata

Name: Useless assignment to global variable

Description: An assignment to a global variable that is never used has no effect.

ID: js/useless-assignment-to-global

Kind: problem

Severity: warning

Precision: low

Query: DeadStoreOfGlobal.ql
/**
 * @name Useless assignment to global variable
 * @description An assignment to a global variable that is never used has no effect.
 * @kind problem
 * @problem.severity warning
 * @id js/useless-assignment-to-global
 * @tags maintainability
 *       correctness
 *       external/cwe/cwe-563
 * @precision low
 */

import javascript

/** Holds if every access to `v` is a write. */
predicate onlyWritten(Variable v) {
  forall(VarAccess va | va = v.getAnAccess() | exists(Assignment assgn | assgn.getTarget() = va))
}

from Variable v, GlobalVarAccess gva
where
  v = gva.getVariable() and
  onlyWritten(v) and
  // 'v' is not externally declared...
  not exists(ExternalVarDecl d | d.getName() = v.getName() |
    // ...as a member of {Window,Worker,WebWorker}.prototype
    d.(ExternalInstanceMemberDecl).getBaseName().regexpMatch("Window|Worker|WebWorker")
    or
    // ...or as a member of window
    d.(ExternalStaticMemberDecl).getBaseName() = "window"
    or
    // ...or as a global
    d instanceof ExternalGlobalDecl
  ) and
  // it isn't declared using a linter directive
  not exists(Linting::GlobalDeclaration decl | decl.declaresGlobalForAccess(gva)) and
  // ignore accesses under 'with', since they may well refer to properties of the with'ed object
  not exists(WithStmt with | with.mayAffect(gva))
select gva, "This definition of " + v.getName() + " is useless, since its value is never read."

If a global variable is only ever assigned to but its value is never read, this could indicate dead code, a typo or a logic error.

Recommendation

Ensure that the name of the variable has not been misspelled. If the assignment refers to an externally defined global variable (such as property of the window object), you can provide an externs file or a JSLint-style /*global ...*/ directive to inform the analysis about this variable.

Example

The following example shows a function for counting the number of leaves in a binary tree. For an inner node, the function first recursively counts the number of leaves in the left and right subtrees, stores them in variables, and then returns their sum. The name of the variable holding the number of leaves in the right subtree has been misspelled: it is spelled rigtLeaves instead of rightLeaves.

Since undeclared variables in JavaScript are assumed to be global by default, this assignment stores the number of leaves in the right subtree in a global variable rigtLeaves, so the algorithm will not work as expected.

function countLeaves(nd) {
	var leftLeaves, rightLeaves;
	
	if (nd.isLeaf)
		return 1;
	
	leftLeaves = countLeaves(nd.left);
	rigtLeaves = countLeaves(nd.right);
	return leftLeaves + rightLeaves;
}

To fix this, correct the name of the local variable:

function countLeaves(nd) {
	var leftLeaves, rightLeaves;
	
	if (nd.isLeaf)
		return 1;
	
	leftLeaves = countLeaves(nd.left);
	rightLeaves = countLeaves(nd.right);
	return leftLeaves + rightLeaves;
}

References