Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

no-self-assign.js 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /**
  2. * @fileoverview Rule to disallow assignments where both sides are exactly the same
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("../util/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. const SPACES = /\s+/g;
  14. /**
  15. * Checks whether the property of 2 given member expression nodes are the same
  16. * property or not.
  17. *
  18. * @param {ASTNode} left - A member expression node to check.
  19. * @param {ASTNode} right - Another member expression node to check.
  20. * @returns {boolean} `true` if the member expressions have the same property.
  21. */
  22. function isSameProperty(left, right) {
  23. if (left.property.type === "Identifier" &&
  24. left.property.type === right.property.type &&
  25. left.property.name === right.property.name &&
  26. left.computed === right.computed
  27. ) {
  28. return true;
  29. }
  30. const lname = astUtils.getStaticPropertyName(left);
  31. const rname = astUtils.getStaticPropertyName(right);
  32. return lname !== null && lname === rname;
  33. }
  34. /**
  35. * Checks whether 2 given member expression nodes are the reference to the same
  36. * property or not.
  37. *
  38. * @param {ASTNode} left - A member expression node to check.
  39. * @param {ASTNode} right - Another member expression node to check.
  40. * @returns {boolean} `true` if the member expressions are the reference to the
  41. * same property or not.
  42. */
  43. function isSameMember(left, right) {
  44. if (!isSameProperty(left, right)) {
  45. return false;
  46. }
  47. const lobj = left.object;
  48. const robj = right.object;
  49. if (lobj.type !== robj.type) {
  50. return false;
  51. }
  52. if (lobj.type === "MemberExpression") {
  53. return isSameMember(lobj, robj);
  54. }
  55. return lobj.type === "Identifier" && lobj.name === robj.name;
  56. }
  57. /**
  58. * Traverses 2 Pattern nodes in parallel, then reports self-assignments.
  59. *
  60. * @param {ASTNode|null} left - A left node to traverse. This is a Pattern or
  61. * a Property.
  62. * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or
  63. * a Property.
  64. * @param {boolean} props - The flag to check member expressions as well.
  65. * @param {Function} report - A callback function to report.
  66. * @returns {void}
  67. */
  68. function eachSelfAssignment(left, right, props, report) {
  69. if (!left || !right) {
  70. // do nothing
  71. } else if (
  72. left.type === "Identifier" &&
  73. right.type === "Identifier" &&
  74. left.name === right.name
  75. ) {
  76. report(right);
  77. } else if (
  78. left.type === "ArrayPattern" &&
  79. right.type === "ArrayExpression"
  80. ) {
  81. const end = Math.min(left.elements.length, right.elements.length);
  82. for (let i = 0; i < end; ++i) {
  83. const rightElement = right.elements[i];
  84. eachSelfAssignment(left.elements[i], rightElement, props, report);
  85. // After a spread element, those indices are unknown.
  86. if (rightElement && rightElement.type === "SpreadElement") {
  87. break;
  88. }
  89. }
  90. } else if (
  91. left.type === "RestElement" &&
  92. right.type === "SpreadElement"
  93. ) {
  94. eachSelfAssignment(left.argument, right.argument, props, report);
  95. } else if (
  96. left.type === "ObjectPattern" &&
  97. right.type === "ObjectExpression" &&
  98. right.properties.length >= 1
  99. ) {
  100. /*
  101. * Gets the index of the last spread property.
  102. * It's possible to overwrite properties followed by it.
  103. */
  104. let startJ = 0;
  105. for (let i = right.properties.length - 1; i >= 0; --i) {
  106. const propType = right.properties[i].type;
  107. if (propType === "SpreadElement" || propType === "ExperimentalSpreadProperty") {
  108. startJ = i + 1;
  109. break;
  110. }
  111. }
  112. for (let i = 0; i < left.properties.length; ++i) {
  113. for (let j = startJ; j < right.properties.length; ++j) {
  114. eachSelfAssignment(
  115. left.properties[i],
  116. right.properties[j],
  117. props,
  118. report
  119. );
  120. }
  121. }
  122. } else if (
  123. left.type === "Property" &&
  124. right.type === "Property" &&
  125. !left.computed &&
  126. !right.computed &&
  127. right.kind === "init" &&
  128. !right.method &&
  129. left.key.name === right.key.name
  130. ) {
  131. eachSelfAssignment(left.value, right.value, props, report);
  132. } else if (
  133. props &&
  134. left.type === "MemberExpression" &&
  135. right.type === "MemberExpression" &&
  136. isSameMember(left, right)
  137. ) {
  138. report(right);
  139. }
  140. }
  141. //------------------------------------------------------------------------------
  142. // Rule Definition
  143. //------------------------------------------------------------------------------
  144. module.exports = {
  145. meta: {
  146. type: "problem",
  147. docs: {
  148. description: "disallow assignments where both sides are exactly the same",
  149. category: "Best Practices",
  150. recommended: true,
  151. url: "https://eslint.org/docs/rules/no-self-assign"
  152. },
  153. schema: [
  154. {
  155. type: "object",
  156. properties: {
  157. props: {
  158. type: "boolean"
  159. }
  160. },
  161. additionalProperties: false
  162. }
  163. ]
  164. },
  165. create(context) {
  166. const sourceCode = context.getSourceCode();
  167. const [{ props = true } = {}] = context.options;
  168. /**
  169. * Reports a given node as self assignments.
  170. *
  171. * @param {ASTNode} node - A node to report. This is an Identifier node.
  172. * @returns {void}
  173. */
  174. function report(node) {
  175. context.report({
  176. node,
  177. message: "'{{name}}' is assigned to itself.",
  178. data: {
  179. name: sourceCode.getText(node).replace(SPACES, "")
  180. }
  181. });
  182. }
  183. return {
  184. AssignmentExpression(node) {
  185. if (node.operator === "=") {
  186. eachSelfAssignment(node.left, node.right, props, report);
  187. }
  188. }
  189. };
  190. }
  191. };