function handleFixes(fixer, unusedVar) {
			const id = unusedVar.identifiers[0];
			const parent = id.parent;
			const parentType = parent.type;
			const tokenBefore = sourceCode.getTokenBefore(id);
			const tokenAfter = sourceCode.getTokenAfter(id);
			const isFunction = astUtils.isFunction;
			const isLoop = astUtils.isLoop;
			const allWriteReferences = unusedVar.references.filter(ref =>
				ref.isWrite(),
			);

			/**
			 * get range from token before of a given node
			 * @param {ASTNode} node node of identifier
			 * @param {number} skips number of token to skip
			 * @returns {number} start range of token before the identifier
			 */
			function getPreviousTokenStart(node, skips) {
				return sourceCode.getTokenBefore(node, skips).range[0];
			}

			/**
			 * get range to token after of a given node
			 * @param {ASTNode} node node of identifier
			 * @param {number} skips number of token to skip
			 * @returns {number} end range of token after the identifier
			 */
			function getNextTokenEnd(node, skips) {
				return sourceCode.getTokenAfter(node, skips).range[1];
			}

			/**
			 * get the value of token before of a given node
			 * @param {ASTNode} node node of identifier
			 * @returns {string} value of token before the identifier
			 */
			function getTokenBeforeValue(node) {
				return sourceCode.getTokenBefore(node).value;
			}

			/**
			 * get the value of token after of a given node
			 * @param {ASTNode} node node of identifier
			 * @returns {string} value of token after the identifier
			 */
			function getTokenAfterValue(node) {
				return sourceCode.getTokenAfter(node).value;
			}

			/**
			 * Check if an array has a single element with null as other element.
			 * @param {ASTNode} node ArrayPattern node
			 * @returns {boolean} true if array has single element with other null elements
			 */
			function hasSingleElement(node) {
				return node.elements.filter(e => e !== null).length === 1;
			}

			/**
			 * check whether import specifier has an import of particular type
			 * @param {ASTNode} node ImportDeclaration node
			 * @param {string} type type of import to check
			 * @returns {boolean} true if import specifier has import of specified type
			 */
			function hasImportOfCertainType(node, type) {
				return node.specifiers.some(e => e.type === type);
			}

			/**
			 * Check whether declaration is safe to remove or not
			 * @param {ASTNode} nextToken next token of unused variable
			 * @param {ASTNode} prevToken previous token of unused variable
			 * @returns {boolean} true if declaration is not safe to remove
			 */
			function isDeclarationNotSafeToRemove(nextToken, prevToken) {
				return (
					nextToken.type === "String" ||
					(prevToken &&
						!astUtils.isSemicolonToken(prevToken) &&
						!astUtils.isOpeningBraceToken(prevToken))
				);
			}

			/**
			 * give fixes for unused variables in function parameters
			 * @param {ASTNode} node node to check
			 * @returns {Object} fixer object
			 */
			function fixFunctionParameters(node) {
				const parentNode = node.parent;

				if (isFunction(parentNode)) {
					// remove unused function parameter if there is only a single parameter
					if (parentNode.params.length === 1) {
						return fixer.removeRange(node.range);
					}

					// remove first unused function parameter when there are multiple parameters
					if (
						getTokenBeforeValue(node) === "(" &&
						getTokenAfterValue(node) === ","
					) {
						return fixer.removeRange([
							node.range[0],
							getNextTokenEnd(node),
						]);
					}

					// remove unused function parameters except first one when there are multiple parameters
					return fixer.removeRange([
						getPreviousTokenStart(node),
						node.range[1],
					]);
				}

				return null;
			}

			/**
			 * fix unused variable declarations and function parameters
			 * @param {ASTNode} node parent node to identifier
			 * @returns {Object} fixer object
			 */
			function fixVariables(node) {
				const parentNode = node.parent;

				// remove unused declared variables such as var a = b; or var a = b, c;
				if (parentNode.type === "VariableDeclarator") {
					// skip variable in for (const [ foo ] of bar);
					if (isLoop(parentNode.parent.parent)) {
						return null;
					}

					/*
					 * remove unused declared variable with single declaration such as 'var a = b;'
					 * remove complete declaration when there is an unused variable in 'const { a } = foo;', same for arrays.
					 */
					if (parentNode.parent.declarations.length === 1) {
						// if next token is a string it could become a directive if node is removed -> no suggestion.
						const nextToken = sourceCode.getTokenAfter(
							parentNode.parent,
						);

						// if previous token exists and is not ";" or "{" not sure about ASI rules -> no suggestion.
						const prevToken = sourceCode.getTokenBefore(
							parentNode.parent,
						);

						if (
							nextToken &&
							isDeclarationNotSafeToRemove(nextToken, prevToken)
						) {
							return null;
						}

						return fixer.removeRange(parentNode.parent.range);
					}

					/*
					 * remove unused declared variable with multiple declaration except first one such as 'var a = b, c = d;'
					 * fix 'let bar = "hello", { a } = foo;' to 'let bar = "hello";' if 'a' is unused, same for arrays.
					 */
					if (getTokenBeforeValue(parentNode) === ",") {
						return fixer.removeRange([
							getPreviousTokenStart(parentNode),
							parentNode.range[1],
						]);
					}

					/*
					 * remove first unused declared variable when there are multiple declarations
					 * fix 'let { a } = foo, bar = "hello";' to 'let  bar = "hello";' if 'a' is unused, same for arrays.
					 */
					return fixer.removeRange([
						parentNode.range[0],
						getNextTokenEnd(parentNode),
					]);
				}

				// fixes [{a: {k}}], [{a: [k]}]
				if (getTokenBeforeValue(node) === ":") {
					if (parentNode.parent.type === "ObjectPattern") {
						// eslint-disable-next-line no-use-before-define -- due to interdependency of functions
						return fixObjectWithValueSeparator(node);
					}
				}

				// fix unused function parameters
				return fixFunctionParameters(node);
			}

			/**
			 * fix nested object like { a: { b } }
			 * @param {ASTNode} node parent node to check
			 * @returns {Object} fixer object
			 */
			function fixNestedObjectVariable(node) {
				const parentNode = node.parent;

				// fix for { a: { b: { c: { d } } } }
				if (
					parentNode.parent.parent.parent.type === "ObjectPattern" &&
					parentNode.parent.properties.length === 1
				) {
					return fixNestedObjectVariable(parentNode.parent);
				}

				// fix for { a: { b } }
				if (parentNode.parent.type === "ObjectPattern") {
					// fix for unused variables in dectructured object with single property in variable decalartion and function parameter
					if (parentNode.parent.properties.length === 1) {
						return fixVariables(parentNode.parent);
					}

					// fix for first unused property when there are multiple properties such as '{ a: { b }, c }'
					if (getTokenBeforeValue(parentNode) === "{") {
						return fixer.removeRange([
							parentNode.range[0],
							getNextTokenEnd(parentNode),
						]);
					}

					// fix for unused property except first one when there are multiple properties such as '{ k, a: { b } }'
					return fixer.removeRange([
						getPreviousTokenStart(parentNode),
						parentNode.range[1],
					]);
				}

				return null;
			}

			/**
			 * fix unused variables in array and nested array
			 * @param {ASTNode} node parent node to check
			 * @returns {Object} fixer object
			 */
			function fixNestedArrayVariable(node) {
				const parentNode = node.parent;

				// fix for nested arrays [[ a ]]
				if (
					parentNode.parent.type === "ArrayPattern" &&
					hasSingleElement(parentNode)
				) {
					return fixNestedArrayVariable(parentNode);
				}

				if (hasSingleElement(parentNode)) {
					// fixes { a: [{ b }] } or { a: [[ b ]] }
					if (getTokenBeforeValue(parentNode) === ":") {
						return fixVariables(parentNode);
					}

					// fixes [a, ...[[ b ]]] or [a, ...[{ b }]]
					if (parentNode.parent.type === "RestElement") {
						// eslint-disable-next-line no-use-before-define -- due to interdependency of functions
						return fixRestInPattern(parentNode.parent);
					}

					// fix unused variables in destructured array in variable declaration or function parameter
					return fixVariables(parentNode);
				}

				// remove last unused array element
				if (
					getTokenBeforeValue(node) === "," &&
					getTokenAfterValue(node) === "]"
				) {
					return fixer.removeRange([
						getPreviousTokenStart(node),
						node.range[1],
					]);
				}

				// remove unused array element
				return fixer.removeRange(node.range);
			}

			/**
			 * fix cases like {a: {k}} or {a: [k]}
			 * @param {ASTNode} node parent node to check
			 * @returns {Object} fixer object
			 */
			function fixObjectWithValueSeparator(node) {
				const parentNode = node.parent.parent;

				// fix cases like [{a : { b }}] or [{a : [ b ]}]
				if (
					parentNode.parent.type === "ArrayPattern" &&
					parentNode.properties.length === 1
				) {
					return fixNestedArrayVariable(parentNode);
				}

				// fix cases like {a: {k}} or {a: [k]}
				return fixNestedObjectVariable(node);
			}

			/**
			 * fix ...[[a]] or ...[{a}] like patterns
			 * @param {ASTNode} node parent node to check
			 * @returns {Object} fixer object
			 */
			function fixRestInPattern(node) {
				const parentNode = node.parent;

				// fix ...[[a]] or ...[{a}] in function parameters
				if (isFunction(parentNode)) {
					if (parentNode.params.length === 1) {
						return fixer.removeRange(node.range);
					}

					return fixer.removeRange([
						getPreviousTokenStart(node),
						node.range[1],
					]);
				}

				// fix rest in nested array pattern like [[a, ...[b]]]
				if (parentNode.type === "ArrayPattern") {
					// fix [[...[b]]]
					if (hasSingleElement(parentNode)) {
						if (parentNode.parent.type === "ArrayPattern") {
							return fixNestedArrayVariable(parentNode);
						}

						// fix 'const [...[b]] = foo; and function foo([...[b]]) {}
						return fixVariables(parentNode);
					}

					// fix [[a, ...[b]]]
					return fixer.removeRange([
						getPreviousTokenStart(node),
						node.range[1],
					]);
				}

				return null;
			}

			// skip fix when variable has references that would be left behind
			if (
				allWriteReferences.some(
					ref => ref.identifier.range[0] !== id.range[0],
				)
			) {
				return null;
			}

			// remove declared variables such as var a; or var a, b;
			if (parentType === "VariableDeclarator") {
				if (parent.parent.declarations.length === 1) {
					// prevent fix of variable in forOf and forIn loops.
					if (
						isLoop(parent.parent.parent) &&
						parent.parent.parent.body !== parent.parent
					) {
						return null;
					}

					// removes only variable not semicolon in 'if (foo()) var bar;' or in 'loops' or in 'with' statement.
					if (
						parent.parent.parent.type === "IfStatement" ||
						isLoop(parent.parent.parent) ||
						(parent.parent.parent.type === "WithStatement" &&
							parent.parent.parent.body === parent.parent)
					) {
						return fixer.replaceText(parent.parent, ";");
					}

					// if next token is a string it could become a directive if node is removed -> no suggestion.
					const nextToken = sourceCode.getTokenAfter(parent.parent);

					// if previous token exists and is not ";" or "{" not sure about ASI rules -> no suggestion.
					const prevToken = sourceCode.getTokenBefore(parent.parent);

					if (
						nextToken &&
						isDeclarationNotSafeToRemove(nextToken, prevToken)
					) {
						return null;
					}

					// remove unused declared variable with single declaration like 'var a = b;'
					return fixer.removeRange(parent.parent.range);
				}

				// remove unused declared variable with multiple declaration except first one like 'var a = b, c = d;'
				if (tokenBefore.value === ",") {
					return fixer.removeRange([
						tokenBefore.range[0],
						parent.range[1],
					]);
				}

				// remove first unused declared variable when there are multiple declarations
				return fixer.removeRange([
					parent.range[0],
					getNextTokenEnd(parent),
				]);
			}

			// remove variables in object patterns
			if (parent.parent.type === "ObjectPattern") {
				if (parent.parent.properties.length === 1) {
					// fix [a, ...{b}]
					if (parent.parent.parent.type === "RestElement") {
						return fixRestInPattern(parent.parent.parent);
					}

					// fix [{ a }]
					if (parent.parent.parent.type === "ArrayPattern") {
						return fixNestedArrayVariable(parent.parent);
					}

					/*
					 * var {a} = foo;
					 * function a({a}) {}
					 * fix const { a: { b } } = foo;
					 */
					return fixVariables(parent.parent);
				}

				// fix const { a:b } = foo;
				if (tokenBefore.value === ":") {
					// remove first unused variable in const { a:b } = foo;
					if (
						getTokenBeforeValue(parent) === "{" &&
						getTokenAfterValue(parent) === ","
					) {
						return fixer.removeRange([
							parent.range[0],
							getNextTokenEnd(parent),
						]);
					}

					// remove unused variables in const { a: b, c: d } = foo; except first one
					return fixer.removeRange([
						getPreviousTokenStart(parent),
						id.range[1],
					]);
				}
			}

			// remove unused variables inside an array
			if (parentType === "ArrayPattern") {
				if (hasSingleElement(parent)) {
					// fix [a, ...[b]]
					if (parent.parent.type === "RestElement") {
						return fixRestInPattern(parent.parent);
					}

					// fix [ [a] ]
					if (parent.parent.type === "ArrayPattern") {
						return fixNestedArrayVariable(parent);
					}

					/*
					 * fix var [a] = foo;
					 * fix function foo([a]) {}
					 * fix const { a: [b] } = foo;
					 */
					return fixVariables(parent);
				}

				// if "a" is unused in [a, b ,c] fixes to [, b, c]
				if (tokenBefore.value === "," && tokenAfter.value === ",") {
					return fixer.removeRange(id.range);
				}
			}

			// remove unused rest elements
			if (parentType === "RestElement") {
				// fix [a, ...rest]
				if (parent.parent.type === "ArrayPattern") {
					if (hasSingleElement(parent.parent)) {
						// fix [[...rest]] when there is only rest element
						if (parent.parent.parent.type === "ArrayPattern") {
							return fixNestedArrayVariable(parent.parent);
						}

						// fix 'const [...rest] = foo;' and 'function foo([...rest]) {}'
						return fixVariables(parent.parent);
					}

					// fix [a, ...rest]
					return fixer.removeRange([
						getPreviousTokenStart(id, 1),
						id.range[1],
					]);
				}

				// fix { a, ...rest}
				if (parent.parent.type === "ObjectPattern") {
					// fix 'const {...rest} = foo;' and 'function foo({...rest}) {}'
					if (parent.parent.properties.length === 1) {
						return fixVariables(parent.parent);
					}

					// fix { a, ...rest} when there are multiple properties
					return fixer.removeRange([
						getPreviousTokenStart(id, 1),
						id.range[1],
					]);
				}

				// fix function foo(...rest) {}
				if (isFunction(parent.parent)) {
					// remove unused rest in function parameter if there is only single parameter
					if (parent.parent.params.length === 1) {
						return fixer.removeRange(parent.range);
					}

					// remove unused rest in function parameter if there multiple parameter
					return fixer.removeRange([
						getPreviousTokenStart(parent),
						parent.range[1],
					]);
				}
			}

			if (parentType === "AssignmentPattern") {
				// fix [a = aDefault]
				if (parent.parent.type === "ArrayPattern") {
					return fixNestedArrayVariable(parent);
				}

				// fix {a = aDefault}
				if (parent.parent.parent.type === "ObjectPattern") {
					if (parent.parent.parent.properties.length === 1) {
						// fixes [{a = aDefault}]
						if (
							parent.parent.parent.parent.type === "ArrayPattern"
						) {
							return fixNestedArrayVariable(parent.parent.parent);
						}

						// fix 'const {a = aDefault} = foo;' and 'function foo({a = aDefault}) {}'
						return fixVariables(parent.parent.parent);
					}

					// fix unused 'a' in {a = aDefault} if it is the first property
					if (
						getTokenBeforeValue(parent.parent) === "{" &&
						getTokenAfterValue(parent.parent) === ","
					) {
						return fixer.removeRange([
							parent.parent.range[0],
							getNextTokenEnd(parent.parent),
						]);
					}

					// fix unused 'b' in {a, b = aDefault} if it is not the first property
					return fixer.removeRange([
						getPreviousTokenStart(parent.parent),
						parent.parent.range[1],
					]);
				}

				// fix unused assignment patterns in function parameters
				if (isFunction(parent.parent)) {
					return fixFunctionParameters(parent);
				}
			}

			// remove unused functions
			if (parentType === "FunctionDeclaration" && parent.id === id) {
				return fixer.removeRange(parent.range);
			}

			// remove unused default import
			if (parentType === "ImportDefaultSpecifier") {
				// remove unused default import when there are not other imports
				if (
					!hasImportOfCertainType(parent.parent, "ImportSpecifier") &&
					!hasImportOfCertainType(
						parent.parent,
						"ImportNamespaceSpecifier",
					)
				) {
					return fixer.removeRange([
						parent.range[0],
						parent.parent.source.range[0],
					]);
				}

				// remove unused default import when there are other imports also
				return fixer.removeRange([id.range[0], tokenAfter.range[1]]);
			}

			if (parentType === "ImportSpecifier") {
				// remove unused imports when there is a single import
				if (
					parent.parent.specifiers.filter(
						e => e.type === "ImportSpecifier",
					).length === 1
				) {
					// remove unused import when there is no default import
					if (
						!hasImportOfCertainType(
							parent.parent,
							"ImportDefaultSpecifier",
						)
					) {
						return fixer.removeRange(parent.parent.range);
					}

					// fixes "import foo from 'module';" to "import 'module';"
					return fixer.removeRange([
						getPreviousTokenStart(parent, 1),
						tokenAfter.range[1],
					]);
				}

				if (getTokenBeforeValue(parent) === "{") {
					return fixer.removeRange([
						parent.range[0],
						getNextTokenEnd(parent),
					]);
				}

				return fixer.removeRange([
					getPreviousTokenStart(parent),
					parent.range[1],
				]);
			}

			if (parentType === "ImportNamespaceSpecifier") {
				if (
					hasImportOfCertainType(
						parent.parent,
						"ImportDefaultSpecifier",
					)
				) {
					return fixer.removeRange([
						getPreviousTokenStart(parent),
						parent.range[1],
					]);
				}

				// fixes "import * as foo from 'module';" to "import 'module';"
				return fixer.removeRange([
					parent.range[0],
					parent.parent.source.range[0],
				]);
			}

			// skip error in catch(error) variable
			if (parentType === "CatchClause") {
				return null;
			}

			// remove unused declared classes
			if (parentType === "ClassDeclaration") {
				return fixer.removeRange(parent.range);
			}

			// remove unused variable that is in a sequence [a,b] fixes to [a]
			if (tokenBefore?.value === ",") {
				return fixer.removeRange([tokenBefore.range[0], id.range[1]]);
			}

			// remove unused variable that is in a sequence inside function arguments and object pattern
			if (tokenAfter.value === ",") {
				// fix function foo(a, b) {}
				if (tokenBefore.value === "(") {
					return fixer.removeRange([
						id.range[0],
						tokenAfter.range[1],
					]);
				}

				// fix const {a, b} = foo;
				if (tokenBefore.value === "{") {
					return fixer.removeRange([
						id.range[0],
						tokenAfter.range[1],
					]);
				}
			}

			if (
				parentType === "ArrowFunctionExpression" &&
				parent.params.length === 1 &&
				tokenAfter?.value !== ")"
			) {
				return fixer.replaceText(id, "()");
			}

			return fixer.removeRange(id.range);
		}
fixes unused variables
@param {Object} fixer fixer object
@param {Object} unusedVar unused variable to fix
@returns {Object} fixer object