docs: def has_code(
      state,
      text,
      incorrect_msg="Check the {ast_path}. The checker expected to find {text}.",
      fixed=False,
  ):
      """Test whether the student code contains text.
  
      Args:
          state: State instance describing student and solution code. Can be omitted if used with Ex().
          text : text that student code must contain. Can be a regex pattern or a simple string.
          incorrect_msg: feedback message if text is not in student code.
          fixed: whether to match text exactly, rather than using regular expressions.
  
      Note:
          Functions like ``check_node`` focus on certain parts of code.
          Using these functions followed by ``has_code`` will only look
          in the code being focused on.
  
      :Example:
          If the student code is.. ::
  
              SELECT a FROM b WHERE id < 100
  
          Then the first test below would (unfortunately) pass, but the second would fail..::
  
              # contained in student code
              Ex().has_code(text="id < 10")
  
              # the $ means that you are matching the end of a line
              Ex().has_code(text="id < 10$")
  
          By setting ``fixed = True``, you can search for fixed strings::
  
              # without fixed = True, '*' matches any character
              Ex().has_code(text="SELECT * FROM b")               # passes
              Ex().has_code(text="SELECT \\\\* FROM b")             # fails
              Ex().has_code(text="SELECT * FROM b", fixed=True)   # fails
  
          You can check only the code corresponding to the WHERE clause, using ::
  
              where = Ex().check_node('SelectStmt', 0).check_edge('where_clause')
              where.has_code(text = "id < 10)
  
      """
      stu_ast = state.student_ast
      stu_code = state.student_code
  
      # fallback on using complete student code if no ast
      ParseError = state.ast_dispatcher.ParseError
  
      def get_text(ast, code):
          if isinstance(ast, ParseError):
              return code
          try:
              return ast.get_text(code)
          except:
              return code
  
      stu_text = get_text(stu_ast, stu_code)
  
      _msg = incorrect_msg.format(
          ast_path=state.get_ast_path() or "highlighted code", text=text
      )
  
      # either simple text matching or regex test
      res = text in stu_text if fixed else re.search(text, stu_text)
  
      if not res:
          state.report(Feedback(_msg))
  
      return state