emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] emacs-26 ca08b69 39/39: Merge branch 'scratch/flymake-refa


From: João Távora
Subject: [Emacs-diffs] emacs-26 ca08b69 39/39: Merge branch 'scratch/flymake-refactor-clean-for-emacs-26' into emacs-26
Date: Tue, 3 Oct 2017 10:04:54 -0400 (EDT)

branch: emacs-26
commit ca08b6954974555ba929b4f9b6b0a52d48d1f8e6
Merge: 0fff900 5d922e5
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>

    Merge branch 'scratch/flymake-refactor-clean-for-emacs-26' into emacs-26
---
 doc/misc/flymake.texi                              |  542 ++---
 lisp/emacs-lisp/bytecomp.el                        |   22 +
 lisp/emacs-lisp/checkdoc.el                        |   19 +-
 lisp/progmodes/elisp-mode.el                       |  171 +-
 lisp/progmodes/flymake-proc.el                     | 1194 ++++++++++
 lisp/progmodes/flymake.el                          | 2319 +++++++-------------
 test/lisp/progmodes/flymake-resources/Makefile     |    4 +-
 .../flymake-resources/errors-and-warnings.c        |   13 +
 .../lisp/progmodes/flymake-resources/no-problems.h |    1 +
 .../progmodes/flymake-resources/some-problems.h    |    5 +
 test/lisp/progmodes/flymake-tests.el               |  297 ++-
 11 files changed, 2752 insertions(+), 1835 deletions(-)

diff --git a/doc/misc/flymake.texi b/doc/misc/flymake.texi
index 1bc416f..5dd72f8 100644
--- a/doc/misc/flymake.texi
+++ b/doc/misc/flymake.texi
@@ -4,7 +4,7 @@
 @set VERSION 0.3
 @set UPDATED April 2004
 @settitle GNU Flymake @value{VERSION}
address@hidden docstyle.texi
address@hidden ../emacs/docstyle.texi
 @syncodeindex pg cp
 @comment %**end of header
 
@@ -35,7 +35,7 @@ modify this GNU manual.''
 @titlepage
 @title GNU Flymake
 @subtitle for version @value{VERSION}, @value{UPDATED}
address@hidden Pavel Kobiakov(@email{pk_at_work@@yahoo.com})
address@hidden Pavel Kobiakov(@email{pk_at_work@@yahoo.com}) and João Távora.
 @page
 @vskip 0pt plus 1filll
 @insertcopying
@@ -53,8 +53,8 @@ modify this GNU manual.''
 * Overview of Flymake::
 * Installing Flymake::
 * Using Flymake::
-* Configuring Flymake::
-* Flymake Implementation::
+* Extending Flymake::
+* The legacy Proc backend::
 * GNU Free Documentation License::
 * Index::
 @end menu
@@ -63,67 +63,56 @@ modify this GNU manual.''
 @chapter Overview
 @cindex Overview of Flymake
 
-Flymake is a universal on-the-fly syntax checker implemented as an
-Emacs minor mode.  Flymake runs the pre-configured syntax check tool
-(compiler for C++ files, @code{perl} for perl files, etc.)@: in the
-background, passing it a temporary copy of the current buffer, and
-parses the output for known error/warning message patterns.  Flymake
-then highlights erroneous lines (i.e., lines for which at least one
-error or warning has been reported by the syntax check tool), and
-displays an overall buffer status in the mode line.  Status information
-displayed by Flymake contains total number of errors and warnings
-reported for the buffer during the last syntax check.
-
address@hidden and @code{flymake-goto-prev-error}
-functions allow for easy navigation to the next/previous erroneous
-line, respectively.
-
-Calling @code{flymake-display-err-menu-for-current-line} will popup a
-menu containing error messages reported by the syntax check tool for
-the current line.  Errors/warnings belonging to another file, such as a
address@hidden header file included by a @code{.c} file, are shown in the
-current buffer as belonging to the first line.  Menu items for such
-messages also contain a filename and a line number.  Selecting such a
-menu item will automatically open the file and jump to the line with
-error.
+Flymake is a universal on-the-fly buffer checker implemented as an
+Emacs minor mode. When enabled, Flymake visually annotates the buffer
+with diagnostic information coming from one or more different sources,
+or @emph{backends}.
+
+Historically, Flymake used to accept diagnostics from a single, albeit
+reasonably flexible, backend.
+
+This backend isn't (yet) obsolete and so is still available as a
+fallback and active by default(@pxref{The legacy Proc backend}). It works by
+selecting a syntax check tool from a preconfigured list (compiler for
+C++ files, @code{perl} for perl files, etc.), and executing it in the
+background, passing it a temporary file which is a copy of the current
+buffer, and parsing the output for known error/warning message
+patterns.
+
+Flymake annotates the buffer by highlighting problematic buffer
+regions with a special space. It also displays an overall buffer
+status in the mode line.  Status information displayed by Flymake
+contains totals for different types of diagnostics.
+
address@hidden and @code{flymake-goto-prev-error} are
+commands that allow easy navigation to the next/previous erroneous
+line, respectively. If might be a good idea to map them to @kbd{M-n}
+and @kbd{M-p} in @code{flymake-mode}, by adding to your init file:
+
address@hidden
+(define-key flymake-mode-map (kbd "M-n") 'flymake-goto-next-error)
+(define-key flymake-mode-map (kbd "M-p") 'flymake-goto-prev-error)
address@hidden lisp
 
 Syntax check is done ``on-the-fly''.  It is started whenever
 
 @itemize @bullet
address@hidden buffer is loaded
address@hidden a newline character is added to the buffer
address@hidden @code{flymake-mode} is started;
address@hidden a newline character is added to the buffer;
 @item some changes were made to the buffer more than @code{0.5} seconds ago 
(the
 delay is configurable).
 @end itemize
 
 Flymake is a universal syntax checker in the sense that it's easily
-extended to support new syntax check tools and error message
-patterns.  @xref{Configuring Flymake}.
+extended to support new backends.  @xref{Customizable variables}.
 
 @node Installing Flymake
 @chapter Installing
 @cindex Installing Flymake
 
-
-Flymake is packaged in a single file, @code{flymake.el}.
-
-To install/update Flymake, place @code{flymake.el} to a directory
-somewhere on Emacs load path.  You might also want to byte-compile
address@hidden to improve performance.
-
-Also, place the following line in the @code{.emacs} file.
-
address@hidden
-(require 'flymake)
address@hidden lisp
-
-You might also map the most frequently used Flymake functions, such as
address@hidden, to some keyboard shortcuts:
-
address@hidden
-(global-set-key [f3] 'flymake-display-err-menu-for-current-line)
-(global-set-key [f4] 'flymake-goto-next-error)
address@hidden lisp
+Flymake is included with Emacs and its main commands, like
address@hidden, are autoloaded. This means there is usually
+nothing to do by way of installation.
 
 @node Using Flymake
 @chapter Using Flymake
@@ -132,10 +121,10 @@ You might also map the most frequently used Flymake 
functions, such as
 @menu
 * Flymake mode::
 * Running the syntax check::
-* Navigating to error lines::
-* Viewing error messages::
+* Navigating to error lines::   @c * Viewing error messages::
 * Syntax check statuses::
 * Troubleshooting::
+* Customizable variables::
 @end menu
 
 @node Flymake mode
@@ -161,10 +150,8 @@ line in @code{.emacs}:
 
 When @code{flymake-mode} is active, syntax check is started
 automatically on any of the three conditions mentioned above.  Syntax
-check can also be started manually by using the
address@hidden function.  This
-can be used, for example, when changes were made to some other buffer
-affecting the current buffer.
+check can also be started manually by using the @code{flymake-start}
+function.
 
 @node Navigating to error lines
 @section Navigating to error lines
@@ -185,21 +172,10 @@ navigate the highlighted lines.
 
 @end multitable
 
-These functions treat erroneous lines as a linked list.  Therefore,
address@hidden will go to the first erroneous line
-when invoked in the end of the buffer.
-
address@hidden Viewing error messages
address@hidden Viewing error messages
address@hidden Viewing error messages
-
-To view error messages belonging to the current line, use the
address@hidden function.  If there's
-at least one error or warning reported for the current line, this
-function will display a popup menu with error/warning texts.
-Selecting the menu item whose error belongs to another file brings
-forward that file with the help of the
address@hidden function.
+If the user option @code{flymake-wrap-around} is active
+(@pxref{Customizable variables}), these functions treat diagnostics
+as a linked list.  Therefore, @code{flymake-goto-next-error} will go
+to the first diagnostic when invoked in the end of the buffer.
 
 @node Syntax check statuses
 @section Syntax check statuses
@@ -209,45 +185,24 @@ After syntax check is finished, its status is displayed 
in the mode line.
 The following statuses are defined.
 
 @multitable @columnfractions 0.25 0.75
address@hidden Flymake* or Flymake:E/W*
address@hidden  Flymake is currently running.  For the second case, E/W 
contains the
-error and warning count for the previous run.
-
address@hidden Flymake
address@hidden  Syntax check is not running.  Usually this means syntax check 
was
-successfully passed (no errors, no warnings).  Other possibilities are:
-syntax check was killed as a result of executing
address@hidden, or syntax check cannot start as compilation
-is currently in progress.
-
address@hidden Flymake:E/W
address@hidden  Number of errors/warnings found by the syntax check process.
-
address@hidden Flymake:!
address@hidden  Flymake was unable to find master file for the current buffer.
address@hidden multitable
-
-The following errors cause a warning message and switch flymake mode
-OFF for the buffer.
-
address@hidden @columnfractions 0.25 0.75
address@hidden CFGERR
address@hidden  Syntax check process returned nonzero exit code, but no
-errors/warnings were reported.  This indicates a possible configuration
-error (for example, no suitable error message patterns for the
-syntax check tool).
-
address@hidden NOMASTER
address@hidden  Flymake was unable to find master file for the current buffer.
-
address@hidden NOMK
address@hidden  Flymake was unable to find a suitable buildfile for the current 
buffer.
-
address@hidden PROCERR
address@hidden  Flymake was unable to launch a syntax check process.
address@hidden @code{Wait}
address@hidden  Some flymake backends haven't reported since the last time they
+where questioned.
+
address@hidden @code{!}
address@hidden All the configured Flymake backends have disabled themselves.
+Left-clicking the ``Flymake'' mode line indicator beings the user
address@hidden log*} buffer where these situations may be investigated
+
address@hidden @code{?}
address@hidden There are no configured Flymake backends in
address@hidden
+
address@hidden @emph{[nerrors nwarnings]}
address@hidden Normal operation, number of errors/warnings found by the syntax
+check process.
 @end multitable
 
-
 @node Troubleshooting
 @section Troubleshooting
 @cindex Logging
@@ -255,70 +210,20 @@ syntax check tool).
 
 Flymake uses a simple logging facility for indicating important points
 in the control flow.  The logging facility sends logging messages to
-the @file{*Messages*} buffer.  The information logged can be used for
+the @file{*Flymake log*} buffer.  The information logged can be used for
 resolving various problems related to Flymake.
 
-Logging output is controlled by the @code{flymake-log-level}
-variable.  @code{3} is the  most verbose level, and @code{-1} switches
-logging off.
-
address@hidden Configuring Flymake
address@hidden Configuring and Extending Flymake
address@hidden Configuring and Extending Flymake
-
address@hidden
-* Customizable variables::
-* Adding support for a new syntax check tool::
address@hidden menu
-
-Flymake was designed to be easily extended for supporting new syntax
-check tools and error message patterns.
+Logging output is controlled by the Emacs @code{warning-minimum-log-level}
+and @code{warning-minimum-level} variables.
 
 @node Customizable variables
 @section Customizable variables
 @cindex Customizable variables
 
-This section summarizes variables used for Flymake
-configuration.
+This section summarizes variables used for the configuration of the
+Flymake user interface.
 
 @table @code
address@hidden flymake-log-level
-Controls logging output, see @ref{Troubleshooting}.
-
address@hidden flymake-allowed-file-name-masks
-A list of @code{(filename-regexp, init-function, cleanup-function
-getfname-function)} for configuring syntax check tools.  @xref{Adding
-support for a new syntax check tool}.
-
address@hidden
address@hidden flymake-buildfile-dirs
-A list of directories (relative paths) for searching a
-buildfile.  @xref{Locating the buildfile}.
address@hidden ignore
-
address@hidden flymake-master-file-dirs
-A list of directories for searching a master file.  @xref{Locating a
-master file}.
-
address@hidden flymake-get-project-include-dirs-function
-A function used for obtaining a list of project include dirs (C/C++
-specific).  @xref{Getting the include directories}.
-
address@hidden flymake-master-file-count-limit
address@hidden flymake-check-file-limit
-Used when looking for a master file.  @xref{Locating a master file}.
-
address@hidden flymake-err-line-patterns
-Patterns for error/warning messages in the form @code{(regexp file-idx
-line-idx col-idx err-text-idx)}.  @xref{Parsing the output}.
-
address@hidden flymake-warning-predicate
-Predicate to classify error text as warning. @xref{Parsing the output}.
-
address@hidden flymake-compilation-prevents-syntax-check
-A flag indicating whether compilation and syntax check of the same
-file cannot be run simultaneously.
-
 @item flymake-no-changes-timeout
 If any changes are made to the buffer, syntax check is automatically
 started after @code{flymake-no-changes-timeout} seconds.
@@ -327,13 +232,17 @@ started after @code{flymake-no-changes-timeout} seconds.
 A boolean flag indicating whether to start syntax check after a
 newline character is added to the buffer.
 
address@hidden flymake-errline
-A custom face for highlighting lines for which at least one error has
-been reported.
address@hidden flymake-error
+A custom face for highlighting regions for which an error has been
+reported.
+
address@hidden flymake-warning
+A custom face for highlighting regions for which a warning has been
+reported.
 
address@hidden flymake-warnline
-A custom face for highlighting lines for which at least one warning
-and no errors have been reported.
address@hidden flymake-note
+A custom face for highlighting regions for which a note has been
+reported.
 
 @item flymake-error-bitmap
 A bitmap used in the fringe to mark lines for which an error has
@@ -346,6 +255,76 @@ been reported.
 @item flymake-fringe-indicator-position
 Which fringe (if any) should show the warning/error bitmaps.
 
address@hidden flymake-wrap-around
+If non-nil, moving to errors with @code{flymake-goto-next-error} and
address@hidden wraps around buffer boundaries.
+
address@hidden table
+
address@hidden Extending Flymake
address@hidden Extending Flymake
address@hidden Extending Flymake
+
address@hidden The legacy Proc backend
address@hidden The legacy ``Proc'' backend
address@hidden The legacy Proc backend
+
address@hidden
+* Proc customization variables::
+* Adding support for a new syntax check tool::
+* Implementation overview::
+* Making a temporary copy::
+* Locating a master file::
+* Getting the include directories::
+* Locating the buildfile::
+* Starting the syntax check process::
+* Parsing the output::
+* Interaction with other modes::
address@hidden menu
+
+The backend @code{flymake-proc-legacy-backend} was originally designed
+to be extended for supporting new syntax check tools and error message
+patterns. It is also controlled by its own set of customization variables
+
address@hidden Proc customization variables
address@hidden Customization variables for the Proc backend
address@hidden Proc customization variables
+
address@hidden @code
address@hidden flymake-proc-allowed-file-name-masks
+A list of @code{(filename-regexp, init-function, cleanup-function
+getfname-function)} for configuring syntax check tools.  @xref{Adding
+support for a new syntax check tool}.
+
address@hidden flymake-proc-master-file-dirs
+A list of directories for searching a master file.  @xref{Locating a
+master file}.
+
address@hidden flymake-proc-get-project-include-dirs-function
+A function used for obtaining a list of project include dirs (C/C++
+specific).  @xref{Getting the include directories}.
+
address@hidden flymake-proc-master-file-count-limit
address@hidden flymake-proc-check-file-limit
+Used when looking for a master file.  @xref{Locating a master file}.
+
address@hidden flymake-proc-err-line-patterns
+Patterns for error/warning messages in the form @code{(regexp file-idx
+line-idx col-idx err-text-idx)}.  @xref{Parsing the output}.
+
address@hidden flymake-proc-diagnostic-type-pred
+A function to classify a diagnostic text as particular type of
+error. Should be a function taking an error text and returning one of
+the symbols indexing @code{flymake-diagnostic-types-alist}. If non-nil
+is returned but there is no such symbol in that table, a warning is
+assumed. If nil is returned, an error is assumed. Can also be a
+regular expression that should match only warnings.  This variable
+replaces the old @code{flymake-warning-re} and
address@hidden
+
address@hidden flymake-proc-compilation-prevents-syntax-check
+A flag indicating whether compilation and syntax check of the same
+file cannot be run simultaneously.
 @end table
 
 @node Adding support for a new syntax check tool
@@ -358,7 +337,7 @@ Which fringe (if any) should show the warning/error bitmaps.
 @end menu
 
 Syntax check tools are configured using the
address@hidden list.  Each item of this list
address@hidden list.  Each item of this list
 has the following format:
 
 @lisp
@@ -369,8 +348,8 @@ has the following format:
 @item filename-regexp
 This field is used as a key for locating init/cleanup/getfname
 functions for the buffer.  Items in
address@hidden are searched sequentially.  The
-first item with @code{filename-regexp} matching buffer filename is
address@hidden are searched sequentially.
+The first item with @code{filename-regexp} matching buffer filename is
 selected.  If no match is found, @code{flymake-mode} is switched off.
 
 @item init-function
@@ -390,8 +369,8 @@ This function is used for translating filenames reported by 
the syntax
 check tool into ``real'' filenames.  Filenames reported by the tool
 will be different from the real ones, as actually the tool works with
 the temporary copy.  In most cases, the default implementation
-provided by Flymake, @code{flymake-get-real-file-name}, can be used as
address@hidden
+provided by Flymake, @code{flymake-proc-get-real-file-name}, can be
+used as @code{getfname-function}.
 
 @end table
 
@@ -399,7 +378,7 @@ To add support for a new syntax check tool, write 
corresponding
 @code{init-function}, and, optionally @code{cleanup-function} and
 @code{getfname-function}.  If the format of error messages reported by
 the new tool is not yet supported by Flymake, add a new entry to
-the @code{flymake-err-line-patterns} list.
+the @code{flymake-proc-err-line-patterns} list.
 
 The following sections contain some examples of configuring Flymake
 support for various syntax check tools.
@@ -415,42 +394,42 @@ checking.
 First, we write the @code{init-function}:
 
 @lisp
-(defun flymake-perl-init ()
-  (let* ((temp-file (flymake-init-create-temp-buffer-copy
-                     'flymake-create-temp-inplace))
+(defun flymake-proc-perl-init ()
+  (let* ((temp-file (flymake-proc-init-create-temp-buffer-copy
+                     'flymake-proc-create-temp-inplace))
          (local-file (file-relative-name
                       temp-file
                       (file-name-directory buffer-file-name))))
     (list "perl" (list "-wc " local-file))))
 @end lisp
 
address@hidden creates a temporary copy of the buffer
address@hidden creates a temporary copy of the buffer
 contents with the help of
address@hidden, and builds an appropriate
address@hidden, and builds an appropriate
 command line.
 
 Next, we add a new entry to the
address@hidden:
address@hidden:
 
 @lisp
-(setq flymake-allowed-file-name-masks
+(setq flymake-proc-allowed-file-name-masks
       (cons '(".+\\.pl$"
-              flymake-perl-init
-              flymake-simple-cleanup
-              flymake-get-real-file-name)
-            flymake-allowed-file-name-masks))
+              flymake-proc-perl-init
+              flymake-proc-simple-cleanup
+              flymake-proc-get-real-file-name)
+            flymake-proc-allowed-file-name-masks))
 @end lisp
 
 Note that we use standard @code{cleanup-function} and
 @code{getfname-function}.
 
-Finally, we add an entry to @code{flymake-err-line-patterns}:
+Finally, we add an entry to @code{flymake-proc-err-line-patterns}:
 
 @lisp
-(setq flymake-err-line-patterns
+(setq flymake-proc-err-line-patterns
       (cons '("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]"
               2 3 nil 1)
-            flymake-err-line-patterns))
+            flymake-proc-err-line-patterns))
 @end lisp
 
 @node Example---Configuring a tool called via make
@@ -462,18 +441,18 @@ In this example we will add support for C files syntax 
checked by
 
 We're not required to write any new functions, as Flymake already has
 functions for @command{make}.  We just add a new entry to the
address@hidden:
address@hidden:
 
 @lisp
-(setq flymake-allowed-file-name-masks
+(setq flymake-proc-allowed-file-name-masks
       (cons '(".+\\.c$"
-              flymake-simple-make-init
-              flymake-simple-cleanup
-              flymake-get-real-file-name)
-            flymake-allowed-file-name-masks))
+              flymake-proc-simple-make-init
+              flymake-proc-simple-cleanup
+              flymake-proc-get-real-file-name)
+            flymake-proc-allowed-file-name-masks))
 @end lisp
 
address@hidden builds the following @command{make}
address@hidden builds the following @command{make}
 command line:
 
 @lisp
@@ -492,7 +471,7 @@ our case this target might look like this:
 
 @verbatim
 check-syntax:
-       gcc -o /dev/null -S ${CHK_SOURCES}
+       gcc -o /dev/null -S ${CHK_SOURCES} || true
 @end verbatim
 
 @noindent
@@ -504,42 +483,25 @@ Automake variable @code{COMPILE}:
 
 @verbatim
 check-syntax:
-       $(COMPILE) -o /dev/null -S ${CHK_SOURCES}
+       $(COMPILE) -o /dev/null -S ${CHK_SOURCES} || true
 @end verbatim
 
address@hidden Flymake Implementation
address@hidden Flymake Implementation
address@hidden Implementation details
-
address@hidden
-* Determining whether syntax check is possible::
-* Making a temporary copy::
-* Locating a master file::
-* Getting the include directories::
-* Locating the buildfile::
-* Starting the syntax check process::
-* Parsing the output::
-* Highlighting erroneous lines::
-* Interaction with other modes::
address@hidden menu
-
-Syntax check is started by calling 
@code{flymake-start-syntax-check-for-current-buffer}.
-Flymake first determines whether it is able to do syntax
-check.  It then saves a copy of the buffer in a temporary file in the
-buffer's directory (or in the system temp directory, for java
-files), creates a syntax check command and launches a process with
-this command.  The output is parsed using a list of error message patterns,
-and error information (file name, line number, type and text) is
-saved.  After the process has finished, Flymake highlights erroneous
-lines in the buffer using the accumulated error information.
-
address@hidden Determining whether syntax check is possible
address@hidden Determining whether syntax check is possible
address@hidden Implementation overview
address@hidden Implementation overview
 @cindex Syntax check models
 @cindex Master file
 
address@hidden saves a copy of the buffer in a
+temporary file in the buffer's directory (or in the system temp
+directory, for java files), creates a syntax check command and
+launches a process with this command.  The output is parsed using a
+list of error message patterns, and error information (file name, line
+number, type and text) is saved.  After the process has finished,
+Flymake highlights erroneous lines in the buffer using the accumulated
+error information.
+
 Syntax check is considered possible if there's an entry in
address@hidden matching buffer's filename and
address@hidden matching buffer's filename and
 its @code{init-function} returns address@hidden value.
 
 Two syntax check modes are distinguished:
@@ -564,10 +526,10 @@ will also check syntax in the current file.  Examples are 
C/C++ (.h,
 These modes are handled inside init/cleanup/getfname functions, see
 @ref{Adding support for a new syntax check tool}.
 
-Flymake contains implementations of all functionality required to
-support different syntax check modes described above (making temporary
-copies, finding master files, etc.), as well as some tool-specific
-(routines for Make, Ant, etc.)@: code.
+The Proc backend contains implementations of all functionality
+required to support different syntax check modes described above
+(making temporary copies, finding master files, etc.), as well as some
+tool-specific (routines for Make, Ant, etc.)@: code.
 
 
 @node Making a temporary copy
@@ -609,15 +571,16 @@ Master file is located in two steps.
 
 First, a list of possible master files is built.  A simple name
 matching is used to find the files.  For a C++ header @code{file.h},
-Flymake searches for all @code{.cpp} files in the directories whose relative 
paths are
-stored in a customizable variable @code{flymake-master-file-dirs}, which
-usually contains something like @code{("." "./src")}.  No more than
address@hidden entries is added to the master file
-list.  The list is then sorted to move files with names @code{file.cpp} to
-the top.
+the Proc backend searches for all @code{.cpp} files in the directories
+whose relative paths are stored in a customizable variable
address@hidden, which usually contains something
+like @code{("." "./src")}.  No more than
address@hidden entries is added to the
+master file list.  The list is then sorted to move files with names
address@hidden to the top.
 
 Next, each master file in a list is checked to contain the appropriate
-include directives.  No more than @code{flymake-check-file-limit} of each
+include directives.  No more than @code{flymake-proc-check-file-limit} of each
 file are parsed.
 
 For @code{file.h}, the include directives to look for are
@@ -639,10 +602,10 @@ and project include directories.  The former is just the 
contents of the
 @code{INCLUDE} environment variable.  The latter is not so easy to obtain,
 and the way it can be obtained can vary greatly for different projects.
 Therefore, a customizable variable
address@hidden is used to provide the
address@hidden is used to provide the
 way to implement the desired behavior.
 
-The default implementation, @code{flymake-get-project-include-dirs-imp},
+The default implementation, @code{flymake-proc-get-project-include-dirs-imp},
 uses a @command{make} call.  This requires a correct base directory, that is, a
 directory containing a correct @file{Makefile}, to be determined.
 
@@ -656,27 +619,27 @@ of every syntax check attempt.
 @cindex buildfile, locating
 @cindex Makefile, locating
 
-Flymake can be configured to use different tools for performing syntax
-checks.  For example, it can use direct compiler call to syntax check a perl
-script or a call to @command{make} for a more complicated case of a
address@hidden/C++} source.  The general idea is that simple files, like perl
-scripts and html pages, can be checked by directly invoking a
-corresponding tool.  Files that are usually more complex and generally
-used as part of larger projects, might require non-trivial options to
-be passed to the syntax check tool, like include directories for
-C++.  The latter files are syntax checked using some build tool, like
-Make or Ant.
+The Proc backend can be configured to use different tools for
+performing syntax checks.  For example, it can use direct compiler
+call to syntax check a perl script or a call to @command{make} for a
+more complicated case of a @code{C/C++} source.  The general idea is
+that simple files, like perl scripts and html pages, can be checked by
+directly invoking a corresponding tool.  Files that are usually more
+complex and generally used as part of larger projects, might require
+non-trivial options to be passed to the syntax check tool, like
+include directories for C++.  The latter files are syntax checked
+using some build tool, like Make or Ant.
 
 All Make configuration data is usually stored in a file called
 @code{Makefile}.  To allow for future extensions, flymake uses a notion of
 buildfile to reference the 'project configuration' file.
 
-Special function, @code{flymake-find-buildfile} is provided for locating 
buildfiles.
+Special function, @code{flymake-proc-find-buildfile} is provided for locating 
buildfiles.
 Searching for a buildfile is done in a manner similar to that of searching
 for possible master files.
 @ignore
 A customizable variable
address@hidden holds a list of relative paths to the
address@hidden holds a list of relative paths to the
 buildfile.  They are checked sequentially until a buildfile is found.
 @end ignore
 In case there's no build file, syntax check is aborted.
@@ -687,12 +650,12 @@ Buildfile values are also cached.
 @section Starting the syntax check process
 @cindex Syntax check process
 
-The command line (command name and the list of arguments) for launching a 
process is returned by the
-initialization function.  Flymake then just calls @code{start-process}
-to start an asynchronous process and configures a process filter and
-sentinel, which are used for processing the output of the syntax check
-tool.  When exiting Emacs, running Flymake processes will be killed
-without prompting the user.
+The command line (command name and the list of arguments) for
+launching a process is returned by the initialization function.  The
+Proc backend then just starts an asynchronous process and configures a
+process filter and sentinel, which are used for processing the output
+of the syntax check tool.  When exiting Emacs, running processes will
+be killed without prompting the user.
 
 @node Parsing the output
 @section Parsing the output
@@ -700,7 +663,7 @@ without prompting the user.
 
 The output generated by the syntax check tool is parsed in the process
 filter/sentinel using the error message patterns stored in the
address@hidden variable.  This variable contains a
address@hidden variable.  This variable contains a
 list of items of the form @code{(regexp file-idx line-idx
 err-text-idx)}, used to determine whether a particular line is an
 error message and extract file name, line number and error text,
@@ -709,66 +672,39 @@ error text with the '@code{^[wW]arning}' pattern.  
Anything that was not
 classified as a warning is considered an error.  Type is then used to
 sort error menu items, which shows error messages first.
 
-Flymake is also able to interpret error message patterns missing err-text-idx
-information.  This is done by merely taking the rest of the matched line
-(@code{(substring line (match-end 0))}) as error text.  This trick allows
-making use of a huge collection of error message line patterns from
address@hidden  All these error patterns are appended to
-the end of @code{flymake-err-line-patterns}.
+The Proc backend is also able to interpret error message patterns
+missing err-text-idx information.  This is done by merely taking the
+rest of the matched line (@code{(substring line (match-end 0))}) as
+error text.  This trick allows making use of a huge collection of
+error message line patterns from @code{compile.el}.  All these error
+patterns are appended to the end of
address@hidden
 
 The error information obtained is saved in a buffer local
 variable.  The buffer for which the process output belongs is
 determined from the address@hidden>@w{}buffer mapping updated
 after every process launch/exit.
 
address@hidden Highlighting erroneous lines
address@hidden Highlighting erroneous lines
address@hidden Erroneous lines, faces
-
-Highlighting is implemented with overlays and happens in the process
-sentinel, after calling the cleanup function.  Two customizable faces
-are used: @code{flymake-errline} and
address@hidden  Errors belonging outside the current
-buffer are considered to belong to line 1 of the current buffer.
-
address@hidden This manual does not use vindex.
address@hidden @vindex flymake-fringe-indicator-position
address@hidden @vindex flymake-error-bitmap
address@hidden @vindex flymake-warning-bitmap
-If the option @code{flymake-fringe-indicator-position} is address@hidden,
-errors and warnings are also highlighted in the left or right fringe,
-using the bitmaps specified by @code{flymake-error-bitmap}
-and @code{flymake-warning-bitmap}.
-
 @node Interaction with other modes
 @section Interaction with other modes
 @cindex Interaction with other modes
 @cindex Interaction with compile mode
 
-The only mode flymake currently knows about is @code{compile}.
+The only mode the Proc backend currently knows about is
address@hidden
 
-Flymake can be configured to not start syntax check if it thinks the
-compilation is in progress.  The check is made by the
address@hidden, which tests the
+The Proc backend can be configured to not start syntax check if it
+thinks the compilation is in progress, by testing the
 @code{compilation-in-progress} variable.  The reason why this might be
 useful is saving CPU time in case both syntax check and compilation
 are very CPU intensive.  The original reason for adding this feature,
 though, was working around a locking problem with MS Visual C++
-compiler.
+compiler.  The variable in question is
address@hidden
 
-Flymake also provides an alternative command for starting compilation,
address@hidden:
-
address@hidden
-(defun flymake-compile ()
-  "Kill all flymake syntax checks then start compilation."
-  (interactive)
-  (flymake-stop-all-syntax-checks)
-  (call-interactively 'compile))
address@hidden lisp
-
-It just kills all the active syntax check processes before calling
address@hidden
+The Proc backend also provides an alternative command for starting
+compilation, @code{flymake-proc-compile}. It just kills all the active
+syntax check processes before calling @code{compile}.
 
 @node GNU Free Documentation License
 @appendix GNU Free Documentation License
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 1b42961..590db57 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -1183,7 +1183,29 @@ Each function's symbol gets added to 
`byte-compile-noruntime-functions'."
           (compilation-forget-errors)
           pt))))
 
+(defvar byte-compile-log-warning-function
+  #'byte-compile--log-warning-for-byte-compile
+  "Function called when encountering a warning or error.
+Called with arguments (STRING POSITION FILL LEVEL).  STRING is a
+message describing the problem.  POSITION is a buffer position
+where the problem was detected.  FILL is a prefix as in
+`warning-fill-prefix'.  LEVEL is the level of the
+problem (`:warning' or `:error').  POSITION, FILL and LEVEL may be
+nil.")
+
 (defun byte-compile-log-warning (string &optional fill level)
+  "Log a byte-compilation warning.
+STRING, FILL and LEVEL are as described in
+`byte-compile-log-warning-function', which see."
+  (funcall byte-compile-log-warning-function
+           string byte-compile-last-position
+           fill
+           level))
+
+(defun byte-compile--log-warning-for-byte-compile (string &optional
+                                                          _position
+                                                          fill
+                                                          level)
   "Log a message STRING in `byte-compile-log-buffer'.
 Also log the current function and file if not already done.  If
 FILL is non-nil, set `warning-fill-prefix' to four spaces.  LEVEL
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 7997ba6..72f82f2 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -1147,14 +1147,27 @@ Prefix argument is the same as for `checkdoc-defun'"
 ;; features and behaviors, so we need some ways of specifying
 ;; them, and making them easier to use in the wacked-out interfaces
 ;; people are requesting
-(defun checkdoc-create-error (text start end &optional unfixable)
-  "Used to create the return error text returned from all engines.
+(defvar checkdoc-create-error-function #'checkdoc--create-error-for-checkdoc
+  "Function called when Checkdoc encounters an error.
+Should accept as arguments (TEXT START END &optional UNFIXABLE).
+
 TEXT is the descriptive text of the error.  START and END define the region
 it is sensible to highlight when describing the problem.
 Optional argument UNFIXABLE means that the error has no auto-fix available.
 
 A list of the form (TEXT START END UNFIXABLE) is returned if we are not
-generating a buffered list of errors."
+generating a buffered list of errors.")
+
+(defun checkdoc-create-error (text start end &optional unfixable)
+  "Used to create the return error text returned from all engines.
+TEXT, START, END and UNFIXABLE conform to
+`checkdoc-create-error-function', which see."
+  (funcall checkdoc-create-error-function text start end unfixable))
+
+(defun checkdoc--create-error-for-checkdoc (text start end &optional unfixable)
+  "Create an error for Checkdoc.
+TEXT, START, END and UNFIXABLE conform to
+`checkdoc-create-error-function', which see."
   (if checkdoc-generate-compile-warnings-flag
       (progn (checkdoc-error start text)
             nil)
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 2f8e081..3690f67 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -243,7 +243,9 @@ Blank lines separate paragraphs.  Semicolons start comments.
   (add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
   (setq-local project-vc-external-roots-function #'elisp-load-path-roots)
   (add-hook 'completion-at-point-functions
-            #'elisp-completion-at-point nil 'local))
+            #'elisp-completion-at-point nil 'local)
+  (add-hook 'flymake-diagnostic-functions #'elisp-flymake-checkdoc nil t)
+  (add-hook 'flymake-diagnostic-functions #'elisp-flymake-byte-compile nil t))
 
 ;; Font-locking support.
 
@@ -810,7 +812,7 @@ non-nil result supercedes the xrefs produced by
   (apply #'nconc
          (let (lst)
            (dolist (sym (apropos-internal regexp))
-            (push (elisp--xref-find-definitions sym) lst))
+             (push (elisp--xref-find-definitions sym) lst))
            (nreverse lst))))
 
 (defvar elisp--xref-identifier-completion-table
@@ -1109,7 +1111,7 @@ If CHAR is not a character, return nil."
           ;; interactive call would use it.
           ;; FIXME: Is it really the right place for this?
           (when (eq (car-safe expr) 'interactive)
-              (setq expr
+           (setq expr
                   `(call-interactively
                     (lambda (&rest args) ,expr args))))
          expr)))))
@@ -1174,7 +1176,7 @@ POS specifies the starting position where EXP was found 
and defaults to point."
             (and (not (special-variable-p var))
                  (save-excursion
                    (zerop (car (syntax-ppss (match-beginning 0)))))
-              (push var vars))))
+                 (push var vars))))
         `(progn ,@(mapcar (lambda (v) `(defvar ,v)) vars) ,exp)))))
 
 (defun eval-last-sexp (eval-last-sexp-arg-internal)
@@ -1379,7 +1381,7 @@ or elsewhere, return a 1-line docstring."
                    (t (help-function-arglist sym)))))
              ;; Stringify, and store before highlighting, downcasing, etc.
             (elisp--last-data-store sym (elisp-function-argstring args)
-                                    'function))))))
+                                     'function))))))
     ;; Highlight, truncate.
     (if argstring
        (elisp--highlight-function-argument
@@ -1588,5 +1590,164 @@ ARGLIST is either a string, or a list of strings or 
symbols."
         (replace-match "(" t t str)
       str)))
 
+;;; Flymake support
+
+;; Don't require checkdoc, but forward declare these checkdoc special
+;; variables. Autoloading them on `checkdoc-current-buffer' is too
+;; late, they won't be bound dynamically.
+(defvar checkdoc-create-error-function)
+(defvar checkdoc-autofix-flag)
+(defvar checkdoc-generate-compile-warnings-flag)
+(defvar checkdoc-diagnostic-buffer)
+(defun elisp-flymake--checkdoc-1 ()
+  "Do actual work for `elisp-flymake-checkdoc'."
+  (let (collected)
+    (let* ((checkdoc-create-error-function
+            (lambda (text start end &optional unfixable)
+              (push (list text start end unfixable) collected)
+              nil))
+           (checkdoc-autofix-flag nil)
+           (checkdoc-generate-compile-warnings-flag nil)
+           (buf (generate-new-buffer " *checkdoc-temp*"))
+           (checkdoc-diagnostic-buffer buf))
+      (unwind-protect
+          (save-excursion
+            (checkdoc-current-buffer t))
+        (kill-buffer buf)))
+    collected))
+
+;;;###autoload
+(defun elisp-flymake-checkdoc (report-fn &rest _args)
+  "A Flymake backend for `checkdoc'.
+Calls REPORT-FN directly."
+  (unless (derived-mode-p 'emacs-lisp-mode)
+    (error "Can only work on `emacs-lisp-mode' buffers"))
+  (funcall report-fn
+           (cl-loop for (text start end _unfixable) in
+                    (elisp-flymake--checkdoc-1)
+                    collect
+                    (flymake-make-diagnostic
+                     (current-buffer)
+                     start end :note text))))
+
+(defun elisp-flymake--byte-compile-done (report-fn
+                                         origin-buffer
+                                         output-buffer
+                                         temp-file)
+  (unwind-protect
+      (with-current-buffer
+          origin-buffer
+        (save-excursion
+          (save-restriction
+            (widen)
+            (funcall
+             report-fn
+             (cl-loop with data =
+                      (with-current-buffer output-buffer
+                        (goto-char (point-min))
+                        (search-forward ":elisp-flymake-output-start")
+                        (read (point-marker)))
+                      for (string pos _fill level) in data
+                      do (goto-char pos)
+                      for beg = (if (< (point) (point-max))
+                                    (point)
+                                  (line-beginning-position))
+                      for end = (min
+                                 (line-end-position)
+                                 (or (cdr
+                                      (bounds-of-thing-at-point 'sexp))
+                                     (point-max)))
+                      collect (flymake-make-diagnostic
+                               (current-buffer)
+                               (if (= beg end) (1- beg) beg)
+                               end
+                               level
+                               string))))))
+    (kill-buffer output-buffer)
+    (ignore-errors (delete-file temp-file))))
+
+(defvar-local elisp-flymake--byte-compile-process nil
+  "Buffer-local process started for byte-compiling the buffer.")
+
+;;;###autoload
+(defun elisp-flymake-byte-compile (report-fn &rest _args)
+  "A Flymake backend for elisp byte compilation.
+Spawn an Emacs process that byte-compiles a file representing the
+current buffer state and calls REPORT-FN when done."
+  (interactive (list (lambda (stuff)
+                       (message "aha %s" stuff))))
+  (unless (derived-mode-p 'emacs-lisp-mode)
+    (error "Can only work on `emacs-lisp-mode' buffers"))
+  (when elisp-flymake--byte-compile-process
+    (process-put elisp-flymake--byte-compile-process 'elisp-flymake--obsolete 
t)
+    (when (process-live-p elisp-flymake--byte-compile-process)
+      (kill-process elisp-flymake--byte-compile-process)))
+  (let ((temp-file (make-temp-file "elisp-flymake-byte-compile"))
+        (origin-buffer (current-buffer)))
+    (save-restriction
+      (widen)
+      (write-region (point-min) (point-max) temp-file nil 'nomessage))
+    (let* ((output-buffer (generate-new-buffer " 
*elisp-flymake-byte-compile*")))
+      (setq
+       elisp-flymake--byte-compile-process
+       (make-process
+        :name "elisp-flymake-byte-compile"
+        :buffer output-buffer
+        :command (list (expand-file-name invocation-name invocation-directory)
+                       "-Q"
+                       "--batch"
+                       ;; "--eval" "(setq load-prefer-newer t)" ; for testing
+                       "-L" default-directory
+                       "-f" "elisp-flymake--batch-compile-for-flymake"
+                       temp-file)
+        :connection-type 'pipe
+        :sentinel
+        (lambda (proc _event)
+          (unless (process-live-p proc)
+            (unwind-protect
+                (cond
+                 ((zerop (process-exit-status proc))
+                  (elisp-flymake--byte-compile-done report-fn
+                                                    origin-buffer
+                                                    output-buffer
+                                                    temp-file))
+                 ((process-get proc 'elisp-flymake--obsolete)
+                  (flymake-log :warning "byte-compile process %s obsolete" 
proc))
+                 (t
+                  (funcall report-fn
+                           :panic
+                           :explanation
+                           (format "byte-compile process %s died" proc)))))))))
+      :stderr null-device
+      :noquery t)))
+
+(defun elisp-flymake--batch-compile-for-flymake (&optional file)
+  "Helper for `elisp-flymake-byte-compile'.
+Runs in a batch-mode Emacs.  Interactively use variable
+`buffer-file-name' for FILE."
+  (interactive (list buffer-file-name))
+  (let* ((file (or file
+                   (car command-line-args-left)))
+         (dummy-elc-file)
+         (byte-compile-log-buffer
+          (generate-new-buffer " *dummy-byte-compile-log-buffer*"))
+         (byte-compile-dest-file-function
+          (lambda (source)
+            (setq dummy-elc-file (make-temp-file (file-name-nondirectory 
source)))))
+         (collected)
+         (byte-compile-log-warning-function
+          (lambda (string &optional position fill level)
+            (push (list string position fill level)
+                  collected)
+            t)))
+    (unwind-protect
+        (byte-compile-file file)
+      (ignore-errors
+        (delete-file dummy-elc-file)
+        (kill-buffer byte-compile-log-buffer)))
+    (prin1 :elisp-flymake-output-start)
+    (terpri)
+    (pp collected)))
+
 (provide 'elisp-mode)
 ;;; elisp-mode.el ends here
diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
new file mode 100644
index 0000000..47ec27f
--- /dev/null
+++ b/lisp/progmodes/flymake-proc.el
@@ -0,0 +1,1194 @@
+;;; flymake-proc.el --- Flymake backend for external tools  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
+
+;; Author:  Pavel Kobyakov <address@hidden>
+;; Maintainer: Leo Liu <address@hidden>
+;; Version: 0.3
+;; Keywords: c languages tools
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.
+;;
+;; This file contains a significant part of the original flymake's
+;; implementation, a buffer-checking mechanism that parses the output
+;; of an external syntax check tool with regular expressions.
+;;
+;; That work has been adapted into a flymake "backend" function,
+;; `flymake-proc-legacy-flymake' suitable for adding to the
+;; `flymake-diagnostic-functions' variable.
+;;
+;;; Bugs/todo:
+
+;; - Only uses "Makefile", not "makefile" or "GNUmakefile"
+;;   (from http://bugs.debian.org/337339).
+
+;;; Code:
+
+(require 'flymake)
+
+(defcustom flymake-proc-compilation-prevents-syntax-check t
+  "If non-nil, don't start syntax check if compilation is running."
+  :group 'flymake
+  :type 'boolean)
+
+(defcustom flymake-proc-xml-program
+  (if (executable-find "xmlstarlet") "xmlstarlet" "xml")
+  "Program to use for XML validation."
+  :type 'file
+  :group 'flymake
+  :version "24.4")
+
+(defcustom flymake-proc-master-file-dirs '("." "./src" "./UnitTest")
+  "Dirs where to look for master files."
+  :group 'flymake
+  :type '(repeat (string)))
+
+(defcustom flymake-proc-master-file-count-limit 32
+  "Max number of master files to check."
+  :group 'flymake
+  :type 'integer)
+
+(defcustom flymake-proc-allowed-file-name-masks
+  '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'"
+     flymake-proc-simple-make-init
+     nil
+     flymake-proc-real-file-name-considering-includes)
+    ("\\.xml\\'" flymake-proc-xml-init)
+    ("\\.html?\\'" flymake-proc-xml-init)
+    ("\\.cs\\'" flymake-proc-simple-make-init)
+    ("\\.p[ml]\\'" flymake-proc-perl-init)
+    ("\\.php[345]?\\'" flymake-proc-php-init)
+    ("\\.h\\'" flymake-proc-master-make-header-init 
flymake-proc-master-cleanup)
+    ("\\.java\\'" flymake-proc-simple-make-java-init 
flymake-proc-simple-java-cleanup)
+    ("[0-9]+\\.tex\\'" flymake-proc-master-tex-init 
flymake-proc-master-cleanup)
+    ("\\.tex\\'" flymake-proc-simple-tex-init)
+    ("\\.idl\\'" flymake-proc-simple-make-init)
+    ;; ("\\.cpp\\'" 1)
+    ;; ("\\.java\\'" 3)
+    ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'")
+    ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 
2))
+    ;; ("\\.idl\\'" 1)
+    ;; ("\\.odl\\'" 1)
+    ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'")
+    ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
+    ;; ("\\.tex\\'" 1)
+    )
+  "Files syntax checking is allowed for.
+This is an alist with elements of the form:
+  REGEXP INIT [CLEANUP [NAME]]
+REGEXP is a regular expression that matches a file name.
+INIT is the init function to use.
+CLEANUP is the cleanup function to use, default `flymake-proc-simple-cleanup'.
+NAME is the file name function to use, default 
`flymake-proc-get-real-file-name'."
+  :group 'flymake
+  :type '(alist :key-type (regexp :tag "File regexp")
+                :value-type
+                (list :tag "Handler functions"
+                      (function :tag "Init function")
+                      (choice :tag "Cleanup function"
+                              (const :tag "flymake-proc-simple-cleanup" nil)
+                              function)
+                      (choice :tag "Name function"
+                              (const :tag "flymake-proc-get-real-file-name" 
nil)
+                              function))))
+
+(defvar-local flymake-proc--current-process nil
+  "Currently active Flymake process for a buffer, if any.")
+
+(defvar flymake-proc--report-fn nil
+  "If bound, function used to report back to flymake's UI.")
+
+(defun flymake-proc-reformat-err-line-patterns-from-compile-el (original-list)
+  "Grab error line patterns from ORIGINAL-LIST in compile.el format.
+Convert it to Flymake internal format."
+  (let* ((converted-list '()))
+    (dolist (item original-list)
+      (setq item (cdr item))
+      (let ((regexp (nth 0 item))
+           (file (nth 1 item))
+           (line (nth 2 item))
+           (col (nth 3 item)))
+       (if (consp file)        (setq file (car file)))
+       (if (consp line)        (setq line (car line)))
+       (if (consp col) (setq col (car col)))
+
+       (when (not (functionp line))
+         (setq converted-list (cons (list regexp file line col) 
converted-list)))))
+    converted-list))
+
+(defvar flymake-proc-err-line-patterns ; regexp file-idx line-idx col-idx 
(optional) text-idx(optional), match-end to end of string is error text
+  (append
+   '(
+     ;; MS Visual C++ 6.0
+     ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : 
\\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
+      1 3 nil 4)
+     ;; jikes
+     ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: 
\\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
+      1 3 nil 4)
+     ;; MS midl
+     ("midl[ ]*:[ ]*\\(command line error .*\\)"
+      nil nil nil 1)
+     ;; MS C#
+     ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): 
\\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
+      1 3 nil 4)
+     ;; perl
+     ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
+     ;; PHP
+     ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 
2 3 nil 1)
+     ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on 
input line \\([0-9]+\\)" 20 3 nil 1)
+     ;; ant/javac.  Note this also matches gcc warnings!
+     (" *\\(\\[javac\\] 
*\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?:[ 
\t\n]*\\(.+\\)"
+      2 4 5 6))
+   ;; compilation-error-regexp-alist)
+   (flymake-proc-reformat-err-line-patterns-from-compile-el 
compilation-error-regexp-alist-alist))
+  "Patterns for matching error/warning lines.  Each pattern has the form
+\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
+Use `flymake-proc-reformat-err-line-patterns-from-compile-el' to add patterns
+from compile.el")
+
+(define-obsolete-variable-alias 'flymake-warning-re 
'flymake-proc-diagnostic-type-pred "26.1")
+(defvar flymake-proc-diagnostic-type-pred
+  'flymake-proc-default-guess
+  "Predicate matching against diagnostic text to detect its type.
+Takes a single argument, the diagnostic's text and should return
+a value suitable for indexing
+`flymake-diagnostic-types-alist' (which see). If the returned
+value is nil, a type of `:error' is assumed. For some backward
+compatibility, if a non-nil value is returned that that doesn't
+index that alist, a type of `:warning' is assumed.
+
+Instead of a function, it can also be a string, a regular
+expression. A match indicates `:warning' type, otherwise
+`:error'")
+
+(defun flymake-proc-default-guess (text)
+  "Guess if TEXT means a warning, a note or an error."
+  (cond ((string-match "^[wW]arning" text)
+         :warning)
+        ((string-match "^[nN]ote" text)
+         :note)
+        (t
+         :error)))
+
+(defun flymake-proc--get-file-name-mode-and-masks (file-name)
+  "Return the corresponding entry from `flymake-proc-allowed-file-name-masks'."
+  (unless (stringp file-name)
+    (error "Invalid file-name"))
+  (let ((fnm flymake-proc-allowed-file-name-masks)
+       (mode-and-masks nil))
+    (while (and (not mode-and-masks) fnm)
+      (if (string-match (car (car fnm)) file-name)
+         (setq mode-and-masks (cdr (car fnm))))
+      (setq fnm (cdr fnm)))
+    (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
+    mode-and-masks))
+
+(defun flymake-proc--get-init-function (file-name)
+  "Return init function to be used for the file."
+  (let* ((init-f  (nth 0 (flymake-proc--get-file-name-mode-and-masks 
file-name))))
+    ;;(flymake-log 0 "calling %s" init-f)
+    ;;(funcall init-f (current-buffer))
+    init-f))
+
+(defun flymake-proc--get-cleanup-function (file-name)
+  "Return cleanup function to be used for the file."
+  (or (nth 1 (flymake-proc--get-file-name-mode-and-masks file-name))
+      'flymake-proc-simple-cleanup))
+
+(defun flymake-proc--get-real-file-name-function (file-name)
+  (or (nth 2 (flymake-proc--get-file-name-mode-and-masks file-name))
+      'flymake-proc-get-real-file-name))
+
+(defvar flymake-proc--find-buildfile-cache (make-hash-table :test #'equal))
+
+(defun flymake-proc--get-buildfile-from-cache (dir-name)
+  "Look up DIR-NAME in cache and return its associated value.
+If DIR-NAME is not found, return nil."
+  (gethash dir-name flymake-proc--find-buildfile-cache))
+
+(defun flymake-proc--add-buildfile-to-cache (dir-name buildfile)
+  "Associate DIR-NAME with BUILDFILE in the buildfile cache."
+  (puthash dir-name buildfile flymake-proc--find-buildfile-cache))
+
+(defun flymake-proc--clear-buildfile-cache ()
+  "Clear the buildfile cache."
+  (clrhash flymake-proc--find-buildfile-cache))
+
+(defun flymake-proc--find-buildfile (buildfile-name source-dir-name)
+  "Find buildfile starting from current directory.
+Buildfile includes Makefile, build.xml etc.
+Return its file name if found, or nil if not found."
+  (or (flymake-proc--get-buildfile-from-cache source-dir-name)
+      (let* ((file (locate-dominating-file source-dir-name buildfile-name)))
+        (if file
+            (progn
+              (flymake-log 3 "found buildfile at %s" file)
+              (flymake-proc--add-buildfile-to-cache source-dir-name file)
+              file)
+          (progn
+            (flymake-log 3 "buildfile for %s not found" source-dir-name)
+            nil)))))
+
+(defun flymake-proc--fix-file-name (name)
+  "Replace all occurrences of `\\' with `/'."
+  (when name
+    (setq name (expand-file-name name))
+    (setq name (abbreviate-file-name name))
+    (setq name (directory-file-name name))
+    name))
+
+(defun flymake-proc--same-files (file-name-one file-name-two)
+  "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
+Return t if so, nil if not."
+  (equal (flymake-proc--fix-file-name file-name-one)
+        (flymake-proc--fix-file-name file-name-two)))
+
+;; This is bound dynamically to pass a parameter to a sort predicate below
+(defvar flymake-proc--included-file-name)
+
+(defun flymake-proc--find-possible-master-files (file-name master-file-dirs 
masks)
+  "Find (by name and location) all possible master files.
+
+Name is specified by FILE-NAME and location is specified by
+MASTER-FILE-DIRS.  Master files include .cpp and .c for .h.
+Files are searched for starting from the .h directory and max
+max-level parent dirs.  File contents are not checked."
+  (let* ((dirs master-file-dirs)
+        (files  nil)
+        (done   nil))
+
+    (while (and (not done) dirs)
+      (let* ((dir (expand-file-name (car dirs) (file-name-directory 
file-name)))
+            (masks masks))
+       (while (and (file-exists-p dir) (not done) masks)
+         (let* ((mask        (car masks))
+                (dir-files   (directory-files dir t mask)))
+
+           (flymake-log 3 "dir %s, %d file(s) for mask %s"
+                        dir (length dir-files) mask)
+           (while (and (not done) dir-files)
+             (when (not (file-directory-p (car dir-files)))
+               (setq files (cons (car dir-files) files))
+               (when (>= (length files) flymake-proc-master-file-count-limit)
+                 (flymake-log 3 "master file count limit (%d) reached" 
flymake-proc-master-file-count-limit)
+                 (setq done t)))
+             (setq dir-files (cdr dir-files))))
+         (setq masks (cdr masks))))
+      (setq dirs (cdr dirs)))
+    (when files
+      (let ((flymake-proc--included-file-name (file-name-nondirectory 
file-name)))
+       (setq files (sort files 'flymake-proc--master-file-compare))))
+    (flymake-log 3 "found %d possible master file(s)" (length files))
+    files))
+
+(defun flymake-proc--master-file-compare (file-one file-two)
+  "Compare two files specified by FILE-ONE and FILE-TWO.
+This function is used in sort to move most possible file names
+to the beginning of the list (File.h -> File.cpp moved to top)."
+  (and (equal (file-name-sans-extension flymake-proc--included-file-name)
+             (file-name-base file-one))
+       (not (equal file-one file-two))))
+
+(defvar flymake-proc-check-file-limit 8192
+  "Maximum number of chars to look at when checking possible master file.
+Nil means search the entire file.")
+
+(defun flymake-proc--check-patch-master-file-buffer
+    (master-file-temp-buffer
+     master-file-name patched-master-file-name
+     source-file-name patched-source-file-name
+     include-dirs regexp)
+  "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
+If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
+instead of SOURCE-FILE-NAME.
+
+For example, foo.cpp is a master file if it includes foo.h.
+
+When a buffer for MASTER-FILE-NAME exists, use it as a source
+instead of reading master file from disk."
+  (let* ((source-file-nondir (file-name-nondirectory source-file-name))
+         (source-file-extension (file-name-extension source-file-nondir))
+         (source-file-nonext (file-name-sans-extension source-file-nondir))
+         (found                     nil)
+        (inc-name                  nil)
+        (search-limit              flymake-proc-check-file-limit))
+    (setq regexp
+          (format regexp       ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
+                  ;; Hack for tex files, where \include often excludes .tex.
+                  ;; Maybe this is safe generally.
+                  (if (and (> (length source-file-extension) 1)
+                           (string-equal source-file-extension "tex"))
+                      (format "%s\\(?:\\.%s\\)?"
+                              (regexp-quote source-file-nonext)
+                              (regexp-quote source-file-extension))
+                    (regexp-quote source-file-nondir))))
+    (unwind-protect
+        (with-current-buffer master-file-temp-buffer
+          (if (or (not search-limit)
+                  (> search-limit (point-max)))
+              (setq search-limit (point-max)))
+          (flymake-log 3 "checking %s against regexp %s"
+                       master-file-name regexp)
+          (goto-char (point-min))
+          (while (and (< (point) search-limit)
+                      (re-search-forward regexp search-limit t))
+            (let ((match-beg   (match-beginning 1))
+                  (match-end   (match-end 1)))
+
+              (flymake-log 3 "found possible match for %s" source-file-nondir)
+              (setq inc-name (match-string 1))
+              (and (> (length source-file-extension) 1)
+                   (string-equal source-file-extension "tex")
+                   (not (string-match (format "\\.%s\\'" source-file-extension)
+                                      inc-name))
+                   (setq inc-name (concat inc-name "." source-file-extension)))
+              (when (eq t (compare-strings
+                           source-file-nondir nil nil
+                           inc-name (- (length inc-name)
+                                       (length source-file-nondir)) nil))
+                (flymake-log 3 "inc-name=%s" inc-name)
+                (when (flymake-proc--check-include source-file-name inc-name
+                                                   include-dirs)
+                  (setq found t)
+                  ;;  replace-match is not used here as it fails in
+                  ;; XEmacs with 'last match not a buffer' error as
+                  ;; check-includes calls replace-in-string
+                  (flymake-proc--replace-region
+                   match-beg match-end
+                   (file-name-nondirectory patched-source-file-name))))
+              (forward-line 1)))
+          (when found
+            (flymake-proc--save-buffer-in-file patched-master-file-name)))
+      ;;+(flymake-log 3 "killing buffer %s"
+      ;;                (buffer-name master-file-temp-buffer))
+      (kill-buffer master-file-temp-buffer))
+    ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found)
+    (when found
+      (flymake-log 2 "found master file %s" master-file-name))
+    found))
+
+;;; XXX: remove
+(defun flymake-proc--replace-region (beg end rep)
+  "Replace text in BUFFER in region (BEG END) with REP."
+  (save-excursion
+    (goto-char end)
+    ;; Insert before deleting, so as to better preserve markers's positions.
+    (insert rep)
+    (delete-region beg end)))
+
+(defun flymake-proc--read-file-to-temp-buffer (file-name)
+  "Insert contents of FILE-NAME into newly created temp buffer."
+  (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat 
"flymake:" (file-name-nondirectory file-name))))))
+    (with-current-buffer temp-buffer
+      (insert-file-contents file-name))
+    temp-buffer))
+
+(defun flymake-proc--copy-buffer-to-temp-buffer (buffer)
+  "Copy contents of BUFFER into newly created temp buffer."
+  (with-current-buffer
+      (get-buffer-create (generate-new-buffer-name
+                          (concat "flymake:" (buffer-name buffer))))
+    (insert-buffer-substring buffer)
+    (current-buffer)))
+
+(defun flymake-proc--check-include (source-file-name inc-name include-dirs)
+  "Check if SOURCE-FILE-NAME can be found in include path.
+Return t if it can be found via include path using INC-NAME."
+  (if (file-name-absolute-p inc-name)
+      (flymake-proc--same-files source-file-name inc-name)
+    (while (and include-dirs
+                (not (flymake-proc--same-files
+                      source-file-name
+                      (concat (file-name-directory source-file-name)
+                              "/" (car include-dirs)
+                              "/" inc-name))))
+      (setq include-dirs (cdr include-dirs)))
+    include-dirs))
+
+(defun flymake-proc--find-buffer-for-file (file-name)
+  "Check if there exists a buffer visiting FILE-NAME.
+Return t if so, nil if not."
+  (let ((buffer-name (get-file-buffer file-name)))
+    (if buffer-name
+       (get-buffer buffer-name))))
+
+(defun flymake-proc--create-master-file (source-file-name 
patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp)
+  "Save SOURCE-FILE-NAME with a different name.
+Find master file, patch and save it."
+  (let* ((possible-master-files     (flymake-proc--find-possible-master-files 
source-file-name flymake-proc-master-file-dirs masks))
+        (master-file-count         (length possible-master-files))
+        (idx                       0)
+        (temp-buffer               nil)
+        (master-file-name          nil)
+        (patched-master-file-name  nil)
+        (found                     nil))
+
+    (while (and (not found) (< idx master-file-count))
+      (setq master-file-name (nth idx possible-master-files))
+      (setq patched-master-file-name (funcall create-temp-f master-file-name 
"flymake_master"))
+      (if (flymake-proc--find-buffer-for-file master-file-name)
+         (setq temp-buffer (flymake-proc--copy-buffer-to-temp-buffer 
(flymake-proc--find-buffer-for-file master-file-name)))
+       (setq temp-buffer (flymake-proc--read-file-to-temp-buffer 
master-file-name)))
+      (setq found
+           (flymake-proc--check-patch-master-file-buffer
+            temp-buffer
+            master-file-name
+            patched-master-file-name
+            source-file-name
+            patched-source-file-name
+            (funcall get-incl-dirs-f (file-name-directory master-file-name))
+            include-regexp))
+      (setq idx (1+ idx)))
+    (if found
+       (list master-file-name patched-master-file-name)
+      (progn
+       (flymake-log 3 "none of %d master file(s) checked includes %s" 
master-file-count
+                    (file-name-nondirectory source-file-name))
+       nil))))
+
+(defun flymake-proc--save-buffer-in-file (file-name)
+  "Save the entire buffer contents into file FILE-NAME.
+Create parent directories as needed."
+  (make-directory (file-name-directory file-name) 1)
+  (write-region nil nil file-name nil 566)
+  (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name))
+
+(defun flymake-proc--diagnostics-for-pattern (proc pattern)
+  (cl-flet ((guess-type
+             (pred message)
+             (cond ((null message)
+                    :error)
+                   ((stringp pred)
+                    (if (string-match pred message)
+                        :warning
+                      :error))
+                   ((functionp pred)
+                    (let ((probe (funcall pred message)))
+                      (cond ((assoc-default probe
+                                            flymake-diagnostic-types-alist)
+                             probe)
+                            (probe
+                             :warning)
+                            (t
+                             :error)))))))
+    (condition-case-unless-debug err
+        (cl-loop
+         with (regexp file-idx line-idx col-idx message-idx) = pattern
+         while (and
+                (search-forward-regexp regexp nil t)
+                ;; If the preceding search spanned more than one line,
+                ;; move to the start of the line we ended up in. This
+                ;; preserves the usefulness of the patterns in
+                ;; `flymake-proc-err-line-patterns', which were
+                ;; written primarily for flymake's original
+                ;; line-by-line parsing and thus never spanned
+                ;; multiple lines.
+                (if (/= (line-number-at-pos (match-beginning 0))
+                        (line-number-at-pos))
+                    (goto-char (line-beginning-position))
+                  t))
+         for fname = (and file-idx (match-string file-idx))
+         for message = (and message-idx (match-string message-idx))
+         for line-string = (and line-idx (match-string line-idx))
+         for line-number = (or (and line-string
+                                    (string-to-number line-string))
+                               1)
+         for col-string = (and col-idx (match-string col-idx))
+         for col-number = (and col-string
+                               (string-to-number col-string))
+         for full-file = (with-current-buffer (process-buffer proc)
+                           (and fname
+                                (funcall
+                                 (flymake-proc--get-real-file-name-function
+                                  fname)
+                                 fname)))
+         for buffer = (and full-file
+                           (find-buffer-visiting full-file))
+         if (and (eq buffer (process-buffer proc)) message)
+         collect (with-current-buffer buffer
+                   (pcase-let ((`(,beg . ,end)
+                                (flymake-diag-region line-number col-number)))
+                     (flymake-make-diagnostic
+                      buffer beg end
+                      (guess-type flymake-proc-diagnostic-type-pred message)
+                      message)))
+         else
+         do (flymake-log 2 "Reference to file %s is out of scope" fname))
+      (error
+       (flymake-log 1 "Error parsing process output for pattern %s: %s"
+                    pattern err)
+       nil))))
+
+(defun flymake-proc--process-filter (proc string)
+  "Parse STRING and collect diagnostics info."
+  (flymake-log 3 "received %d byte(s) of output from process %d"
+               (length string) (process-id proc))
+  (let ((output-buffer (process-get proc 'flymake-proc--output-buffer)))
+    (when (and (buffer-live-p (process-buffer proc))
+               output-buffer)
+      (with-current-buffer output-buffer
+        (let ((moving (= (point) (process-mark proc)))
+              (inhibit-read-only t)
+              (unprocessed-mark
+               (or (process-get proc 'flymake-proc--unprocessed-mark)
+                   (set-marker (make-marker) (point-min)))))
+          (save-excursion
+            ;; Insert the text, advancing the process marker.
+            (goto-char (process-mark proc))
+            (insert string)
+            (set-marker (process-mark proc) (point)))
+          (if moving (goto-char (process-mark proc)))
+
+          ;; check for new diagnostics
+          ;;
+          (save-excursion
+            (goto-char unprocessed-mark)
+            (dolist (pattern flymake-proc-err-line-patterns)
+              (let ((new (flymake-proc--diagnostics-for-pattern proc pattern)))
+                (process-put
+                 proc
+                 'flymake-proc--collected-diagnostics
+                 (append new
+                         (process-get proc
+                                      'flymake-proc--collected-diagnostics)))))
+            (process-put proc 'flymake-proc--unprocessed-mark
+                         (point-marker))))))))
+
+(defun flymake-proc--process-sentinel (proc _event)
+  "Sentinel for syntax check buffers."
+  (let (debug
+        (pid (process-id proc))
+        (source-buffer (process-buffer proc)))
+    (unwind-protect
+        (when (buffer-live-p source-buffer)
+          (with-current-buffer source-buffer
+            (cond ((process-get proc 'flymake-proc--obsolete)
+                   (flymake-log 3 "proc %s considered obsolete"
+                                pid))
+                  ((process-get proc 'flymake-proc--interrupted)
+                   (flymake-log 3 "proc %s interrupted by user"
+                                pid))
+                  ((not (process-live-p proc))
+                   (let* ((exit-status   (process-exit-status proc))
+                          (command       (process-command proc))
+                          (diagnostics (process-get
+                                        proc
+                                        'flymake-proc--collected-diagnostics)))
+                     (flymake-log 2 "process %d exited with code %d"
+                                  pid exit-status)
+                     (cond
+                      ((equal 0 exit-status)
+                       (funcall flymake-proc--report-fn diagnostics
+                                :explanation (format "a gift from %s" 
(process-id proc))
+                                ))
+                      (diagnostics
+                       ;; non-zero exit but some diagnostics is quite
+                       ;; normal...
+                       (funcall flymake-proc--report-fn diagnostics
+                                :explanation (format "a gift from %s" 
(process-id proc))))
+                      ((null diagnostics)
+                       ;; ...but no diagnostics is strange, so panic.
+                       (setq debug debug-on-error)
+                       (flymake-proc--panic
+                        :configuration-error
+                        (format "Command %s errored, but no diagnostics"
+                                command)))))))))
+      (let ((output-buffer (process-get proc 'flymake-proc--output-buffer)))
+        (cond (debug
+               (flymake-log 3 "Output buffer %s kept alive for debugging"
+                            output-buffer))
+              (t
+               (when (buffer-live-p source-buffer)
+                 (with-current-buffer source-buffer
+                   (let ((cleanup-f (flymake-proc--get-cleanup-function
+                                     (buffer-file-name))))
+                     (flymake-log 3 "cleaning up using %s" cleanup-f)
+                     (funcall cleanup-f))))
+               (kill-buffer output-buffer)))))))
+
+(defun flymake-proc--panic (problem explanation)
+  "Tell Flymake UI about a fatal PROBLEM with this backend.
+May only be called in a dynamic environment where
+`flymake-proc--dynamic-report-fn' is bound"
+  (flymake-log 0 "%s: %s" problem explanation)
+  (if (and (boundp 'flymake-proc--report-fn)
+           flymake-proc--report-fn)
+      (funcall flymake-proc--report-fn :panic
+               :explanation (format "%s: %s" problem explanation))
+    (flymake-error "Trouble telling flymake-ui about problem %s(%s)"
+                   problem explanation)))
+
+(require 'compile)
+
+(defun flymake-proc-get-project-include-dirs-imp (basedir)
+  "Include dirs for the project current file belongs to."
+  (if (flymake-proc--get-project-include-dirs-from-cache basedir)
+      (progn
+       (flymake-proc--get-project-include-dirs-from-cache basedir))
+    ;;else
+    (let* ((command-line  (concat "make -C "
+                                 (shell-quote-argument basedir)
+                                 " DUMPVARS=INCLUDE_DIRS dumpvars"))
+          (output        (shell-command-to-string command-line))
+          (lines         (split-string output "\n" t))
+          (count         (length lines))
+          (idx           0)
+          (inc-dirs      nil))
+      (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx 
lines))))
+       (setq idx (1+ idx)))
+      (when (< idx count)
+       (let* ((inc-lines  (split-string (nth idx lines) " *-I" t))
+              (inc-count  (length inc-lines)))
+         (while (> inc-count 0)
+           (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) 
inc-lines)))
+             (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) 
inc-lines)) inc-dirs))
+           (setq inc-count (1- inc-count)))))
+      (flymake-proc--add-project-include-dirs-to-cache basedir inc-dirs)
+      inc-dirs)))
+
+(defvar flymake-proc-get-project-include-dirs-function 
#'flymake-proc-get-project-include-dirs-imp
+  "Function used to get project include dirs, one parameter: basedir name.")
+
+(defun flymake-proc--get-project-include-dirs (basedir)
+  (funcall flymake-proc-get-project-include-dirs-function basedir))
+
+(defun flymake-proc--get-system-include-dirs ()
+  "System include dirs - from the `INCLUDE' env setting."
+  (let* ((includes (getenv "INCLUDE")))
+    (if includes (split-string includes path-separator t) nil)))
+
+(defvar flymake-proc--project-include-dirs-cache (make-hash-table :test 
#'equal))
+
+(defun flymake-proc--get-project-include-dirs-from-cache (base-dir)
+  (gethash base-dir flymake-proc--project-include-dirs-cache))
+
+(defun flymake-proc--add-project-include-dirs-to-cache (base-dir include-dirs)
+  (puthash base-dir include-dirs flymake-proc--project-include-dirs-cache))
+
+(defun flymake-proc--clear-project-include-dirs-cache ()
+  (clrhash flymake-proc--project-include-dirs-cache))
+
+(defun flymake-proc-get-include-dirs (base-dir)
+  "Get dirs to use when resolving local file names."
+  (let* ((include-dirs (append '(".") (flymake-proc--get-project-include-dirs 
base-dir) (flymake-proc--get-system-include-dirs))))
+    include-dirs))
+
+;; (defun flymake-proc--restore-formatting ()
+;;   "Remove any formatting made by flymake."
+;;   )
+
+;; (defun flymake-proc--get-program-dir (buffer)
+;;   "Get dir to start program in."
+;;   (unless (bufferp buffer)
+;;     (error "Invalid buffer"))
+;;   (with-current-buffer buffer
+;;     default-directory))
+
+(defun flymake-proc--safe-delete-file (file-name)
+  (when (and file-name (file-exists-p file-name))
+    (delete-file file-name)
+    (flymake-log 2 "deleted file %s" file-name)))
+
+(defun flymake-proc--safe-delete-directory (dir-name)
+  (condition-case-unless-debug nil
+      (progn
+       (delete-directory dir-name)
+       (flymake-log 2 "deleted dir %s" dir-name))
+    (error
+     (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
+
+
+(defun flymake-proc-legacy-flymake (report-fn &rest args)
+  "Flymake backend based on the original Flymake implementation.
+This function is suitable for inclusion in
+`flymake-diagnostic-types-alist'. For backward compatibility, it
+can also be executed interactively independently of
+`flymake-mode'."
+  ;; Interactively, behave as if flymake had invoked us through its
+  ;; `flymake-diagnostic-functions' with a suitable ID so flymake can
+  ;; clean up consistently
+  (interactive (list
+                (lambda (diags &rest args)
+                  (apply (flymake-make-report-fn 'flymake-proc-legacy-flymake)
+                         diags
+                         (append args '(:force t))))
+                :interactive t))
+  (let ((interactive (plist-get args :interactive))
+        (proc flymake-proc--current-process)
+        (flymake-proc--report-fn report-fn))
+    (when (processp proc)
+      (process-put proc 'flymake-proc--obsolete t)
+      (flymake-log 3 "marking %s obsolete" (process-id proc))
+      (when (process-live-p proc)
+        (when interactive
+          (user-error
+           "There's already a Flymake process running in this buffer")
+          (kill-process proc))))
+    (when
+        ;; A number of situations make us not want to error right away
+        ;; (and disable ourselves), in case the situation changes in
+        ;; the near future.
+        (and buffer-file-name
+             ;; Since we write temp files in current dir, there's no point
+             ;; trying if the directory is read-only (bug#8954).
+             (file-writable-p (file-name-directory buffer-file-name))
+             (or (not flymake-proc-compilation-prevents-syntax-check)
+                 (not (flymake-proc--compilation-is-running))))
+      (let ((init-f (flymake-proc--get-init-function buffer-file-name)))
+        (unless init-f (error "Can find a suitable init function"))
+        (flymake-proc--clear-buildfile-cache)
+        (flymake-proc--clear-project-include-dirs-cache)
+
+        (let* ((cleanup-f (flymake-proc--get-cleanup-function 
buffer-file-name))
+               (cmd-and-args (funcall init-f))
+               (cmd          (nth 0 cmd-and-args))
+               (args         (nth 1 cmd-and-args))
+               (dir          (nth 2 cmd-and-args))
+               (success nil))
+          (unwind-protect
+              (cond
+               ((not cmd-and-args)
+                (flymake-log 0 "init function %s for %s failed, cleaning up"
+                             init-f buffer-file-name))
+               (t
+                (setq flymake-last-change-time nil)
+                (setq proc
+                      (let ((default-directory (or dir default-directory)))
+                        (when dir
+                          (flymake-log 3 "starting process on dir %s" dir))
+                        (make-process
+                         :name "flymake-proc"
+                         :buffer (current-buffer)
+                         :command (cons cmd args)
+                         :noquery t
+                         :filter
+                         (lambda (proc string)
+                           (let ((flymake-proc--report-fn report-fn))
+                             (flymake-proc--process-filter proc string)))
+                         :sentinel
+                         (lambda (proc event)
+                           (let ((flymake-proc--report-fn report-fn))
+                             (flymake-proc--process-sentinel proc event))))))
+                (process-put proc 'flymake-proc--output-buffer
+                             (generate-new-buffer
+                              (format " *flymake output for %s*" 
(current-buffer))))
+                (setq flymake-proc--current-process proc)
+                (flymake-log 2 "started process %d, command=%s, dir=%s"
+                             (process-id proc) (process-command proc)
+                             default-directory)
+                (setq success t)))
+            (unless success
+              (funcall cleanup-f))))))))
+
+(define-obsolete-function-alias 'flymake-start-syntax-check
+  'flymake-proc-legacy-flymake "26.1")
+
+(defun flymake-proc-stop-all-syntax-checks (&optional reason)
+  "Kill all syntax check processes."
+  (interactive (list "Interrupted by user"))
+  (dolist (buf (buffer-list))
+    (with-current-buffer buf
+      (let (p flymake-proc--current-process)
+        (when (process-live-p p)
+          (kill-process p)
+          (process-put p 'flymake-proc--interrupted reason)
+          (flymake-log 2 "killed process %d" (process-id p)))))))
+
+(defun flymake-proc--compilation-is-running ()
+  (and (boundp 'compilation-in-progress)
+       compilation-in-progress))
+
+(defun flymake-proc-compile ()
+  "Kill all Flymake syntax checks, start compilation."
+  (interactive)
+  (flymake-proc-stop-all-syntax-checks "Stopping for proper compilation")
+  (call-interactively 'compile))
+
+;;;; general init-cleanup and helper routines
+(defun flymake-proc-create-temp-inplace (file-name prefix)
+  (unless (stringp file-name)
+    (error "Invalid file-name"))
+  (or prefix
+      (setq prefix "flymake"))
+  (let* ((ext (file-name-extension file-name))
+        (temp-name (file-truename
+                    (concat (file-name-sans-extension file-name)
+                            "_" prefix
+                            (and ext (concat "." ext))))))
+    (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
+    temp-name))
+
+(defun flymake-proc-create-temp-with-folder-structure (file-name _prefix)
+  (unless (stringp file-name)
+    (error "Invalid file-name"))
+
+  (let* ((dir       (file-name-directory file-name))
+         ;; Not sure what this slash-pos is all about, but I guess it's just
+         ;; trying to remove the leading / of absolute file names.
+        (slash-pos (string-match "/" dir))
+        (temp-dir  (expand-file-name (substring dir (1+ slash-pos))
+                                      temporary-file-directory)))
+
+    (file-truename (expand-file-name (file-name-nondirectory file-name)
+                                     temp-dir))))
+
+(defun flymake-proc--delete-temp-directory (dir-name)
+  "Attempt to delete temp dir created by 
`flymake-proc-create-temp-with-folder-structure', do not fail on error."
+  (let* ((temp-dir    temporary-file-directory)
+        (suffix      (substring dir-name (1+ (length temp-dir)))))
+
+    (while (> (length suffix) 0)
+      (setq suffix (directory-file-name suffix))
+      ;;+(flymake-log 0 "suffix=%s" suffix)
+      (flymake-proc--safe-delete-directory
+       (file-truename (expand-file-name suffix temp-dir)))
+      (setq suffix (file-name-directory suffix)))))
+
+(defvar-local flymake-proc--temp-source-file-name nil)
+(defvar-local flymake-proc--master-file-name nil)
+(defvar-local flymake-proc--temp-master-file-name nil)
+(defvar-local flymake-proc--base-dir nil)
+
+(defun flymake-proc-init-create-temp-buffer-copy (create-temp-f)
+  "Make a temporary copy of the current buffer, save its name in buffer data 
and return the name."
+  (let*  ((source-file-name       buffer-file-name)
+         (temp-source-file-name  (funcall create-temp-f source-file-name 
"flymake")))
+
+    (flymake-proc--save-buffer-in-file temp-source-file-name)
+    (setq flymake-proc--temp-source-file-name temp-source-file-name)
+    temp-source-file-name))
+
+(defun flymake-proc-simple-cleanup ()
+  "Do cleanup after `flymake-proc-init-create-temp-buffer-copy'.
+Delete temp file."
+  (flymake-proc--safe-delete-file flymake-proc--temp-source-file-name)
+  (setq flymake-last-change-time nil))
+
+(defun flymake-proc-get-real-file-name (file-name-from-err-msg)
+  "Translate file name from error message to \"real\" file name.
+Return full-name.  Names are real, not patched."
+  (let* ((real-name            nil)
+        (source-file-name      buffer-file-name)
+        (master-file-name      flymake-proc--master-file-name)
+        (temp-source-file-name flymake-proc--temp-source-file-name)
+        (temp-master-file-name flymake-proc--temp-master-file-name)
+        (base-dirs
+          (list flymake-proc--base-dir
+                (file-name-directory source-file-name)
+                (if master-file-name (file-name-directory master-file-name))))
+        (files (list (list source-file-name       source-file-name)
+                      (list temp-source-file-name  source-file-name)
+                      (list master-file-name       master-file-name)
+                      (list temp-master-file-name  master-file-name))))
+
+    (when (equal 0 (length file-name-from-err-msg))
+      (setq file-name-from-err-msg source-file-name))
+
+    (setq real-name (flymake-proc--get-full-patched-file-name 
file-name-from-err-msg base-dirs files))
+    ;; if real-name is nil, than file name from err msg is none of the files 
we've patched
+    (if (not real-name)
+       (setq real-name (flymake-proc--get-full-nonpatched-file-name 
file-name-from-err-msg base-dirs)))
+    (if (not real-name)
+       (setq real-name file-name-from-err-msg))
+    (setq real-name (flymake-proc--fix-file-name real-name))
+    (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" 
file-name-from-err-msg real-name)
+    real-name))
+
+(defun flymake-proc--get-full-patched-file-name (file-name-from-err-msg 
base-dirs files)
+  (let* ((base-dirs-count  (length base-dirs))
+        (file-count       (length files))
+        (real-name        nil))
+
+    (while (and (not real-name) (> base-dirs-count 0))
+      (setq file-count (length files))
+      (while (and (not real-name) (> file-count 0))
+       (let* ((this-dir        (nth (1- base-dirs-count) base-dirs))
+              (this-file       (nth 0 (nth (1- file-count) files)))
+              (this-real-name  (nth 1 (nth (1- file-count) files))))
+         ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" 
this-dir this-file this-real-name file-name-from-err-msg)
+         (when (and this-dir this-file (flymake-proc--same-files
+                                        (expand-file-name 
file-name-from-err-msg this-dir)
+                                        this-file))
+           (setq real-name this-real-name)))
+       (setq file-count (1- file-count)))
+      (setq base-dirs-count (1- base-dirs-count)))
+    real-name))
+
+(defun flymake-proc--get-full-nonpatched-file-name (file-name-from-err-msg 
base-dirs)
+  (let* ((real-name  nil))
+    (if (file-name-absolute-p file-name-from-err-msg)
+       (setq real-name file-name-from-err-msg)
+      (let* ((base-dirs-count  (length base-dirs)))
+       (while (and (not real-name) (> base-dirs-count 0))
+         (let* ((full-name (expand-file-name file-name-from-err-msg
+                                             (nth (1- base-dirs-count) 
base-dirs))))
+           (if (file-exists-p full-name)
+               (setq real-name full-name))
+           (setq base-dirs-count (1- base-dirs-count))))))
+    real-name))
+
+(defun flymake-proc--init-find-buildfile-dir (source-file-name buildfile-name)
+  "Find buildfile, store its dir in buffer data and return its dir, if found."
+  (let* ((buildfile-dir
+          (flymake-proc--find-buildfile buildfile-name
+                                        (file-name-directory 
source-file-name))))
+    (if buildfile-dir
+        (setq flymake-proc--base-dir buildfile-dir)
+      (flymake-proc--panic
+       "NOMK" (format "No buildfile (%s) found for %s"
+                      buildfile-name source-file-name)))))
+
+(defun flymake-proc--init-create-temp-source-and-master-buffer-copy 
(get-incl-dirs-f create-temp-f master-file-masks include-regexp)
+  "Find master file (or buffer), create its copy along with a copy of the 
source file."
+  (let* ((source-file-name       buffer-file-name)
+        (temp-source-file-name  (flymake-proc-init-create-temp-buffer-copy 
create-temp-f))
+        (master-and-temp-master (flymake-proc--create-master-file
+                                 source-file-name temp-source-file-name
+                                 get-incl-dirs-f create-temp-f
+                                 master-file-masks include-regexp)))
+
+    (if (not master-and-temp-master)
+       (progn
+          (flymake-proc--panic
+           "NOMASTER"
+           (format-message "cannot find master file for %s"
+                           source-file-name))
+          nil)
+      (setq flymake-proc--master-file-name (nth 0 master-and-temp-master))
+      (setq flymake-proc--temp-master-file-name (nth 1 
master-and-temp-master)))))
+
+(defun flymake-proc-master-cleanup ()
+  (flymake-proc-simple-cleanup)
+  (flymake-proc--safe-delete-file flymake-proc--temp-master-file-name))
+
+;;;; make-specific init-cleanup routines
+(defun flymake-proc--get-syntax-check-program-args (source-file-name base-dir 
use-relative-base-dir use-relative-source get-cmd-line-f)
+  "Create a command line for syntax check using GET-CMD-LINE-F."
+  (funcall get-cmd-line-f
+           (if use-relative-source
+               (file-relative-name source-file-name base-dir)
+             source-file-name)
+           (if use-relative-base-dir
+               (file-relative-name base-dir
+                                   (file-name-directory source-file-name))
+             base-dir)))
+
+(defun flymake-proc-get-make-cmdline (source base-dir)
+  (list "make"
+       (list "-s"
+             "-C"
+             base-dir
+             (concat "CHK_SOURCES=" source)
+             "SYNTAX_CHECK_MODE=1"
+             "check-syntax")))
+
+(defun flymake-proc-get-ant-cmdline (source base-dir)
+  (list "ant"
+       (list "-buildfile"
+             (concat base-dir "/" "build.xml")
+             (concat "-DCHK_SOURCES=" source)
+             "check-syntax")))
+
+(defun flymake-proc-simple-make-init-impl (create-temp-f use-relative-base-dir 
use-relative-source build-file-name get-cmdline-f)
+  "Create syntax check command line for a directly checked source file.
+Use CREATE-TEMP-F for creating temp copy."
+  (let* ((args nil)
+        (source-file-name   buffer-file-name)
+        (buildfile-dir      (flymake-proc--init-find-buildfile-dir 
source-file-name build-file-name)))
+    (if buildfile-dir
+       (let* ((temp-source-file-name  
(flymake-proc-init-create-temp-buffer-copy create-temp-f)))
+         (setq args (flymake-proc--get-syntax-check-program-args 
temp-source-file-name buildfile-dir
+                                                                 
use-relative-base-dir use-relative-source
+                                                                 
get-cmdline-f))))
+    args))
+
+(defun flymake-proc-simple-make-init ()
+  (flymake-proc-simple-make-init-impl 'flymake-proc-create-temp-inplace t t 
"Makefile" 'flymake-proc-get-make-cmdline))
+
+(defun flymake-proc-master-make-init (get-incl-dirs-f master-file-masks 
include-regexp)
+  "Create make command line for a source file checked via master file 
compilation."
+  (let* ((make-args nil)
+        (temp-master-file-name 
(flymake-proc--init-create-temp-source-and-master-buffer-copy
+                                 get-incl-dirs-f 
'flymake-proc-create-temp-inplace
+                                master-file-masks include-regexp)))
+    (when temp-master-file-name
+      (let* ((buildfile-dir (flymake-proc--init-find-buildfile-dir 
temp-master-file-name "Makefile")))
+       (if  buildfile-dir
+           (setq make-args (flymake-proc--get-syntax-check-program-args
+                            temp-master-file-name buildfile-dir nil nil 
'flymake-proc-get-make-cmdline)))))
+    make-args))
+
+(defun flymake-proc--find-make-buildfile (source-dir)
+  (flymake-proc--find-buildfile "Makefile" source-dir))
+
+;;;; .h/make specific
+(defun flymake-proc-master-make-header-init ()
+  (flymake-proc-master-make-init
+   'flymake-proc-get-include-dirs
+   '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
+   "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
+
+(defun flymake-proc-real-file-name-considering-includes (scraped)
+  (flymake-proc-get-real-file-name
+   (let ((case-fold-search t))
+     (replace-regexp-in-string "^in file included from[ \t*]"
+                               ""
+                               scraped))))
+
+;;;; .java/make specific
+(defun flymake-proc-simple-make-java-init ()
+  (flymake-proc-simple-make-init-impl 
'flymake-proc-create-temp-with-folder-structure nil nil "Makefile" 
'flymake-proc-get-make-cmdline))
+
+(defun flymake-proc-simple-ant-java-init ()
+  (flymake-proc-simple-make-init-impl 
'flymake-proc-create-temp-with-folder-structure nil nil "build.xml" 
'flymake-proc-get-ant-cmdline))
+
+(defun flymake-proc-simple-java-cleanup ()
+  "Cleanup after `flymake-proc-simple-make-java-init' -- delete temp file and 
dirs."
+  (flymake-proc--safe-delete-file flymake-proc--temp-source-file-name)
+  (when flymake-proc--temp-source-file-name
+    (flymake-proc--delete-temp-directory
+     (file-name-directory flymake-proc--temp-source-file-name))))
+
+;;;; perl-specific init-cleanup routines
+(defun flymake-proc-perl-init ()
+  (let* ((temp-file   (flymake-proc-init-create-temp-buffer-copy
+                       'flymake-proc-create-temp-inplace))
+        (local-file  (file-relative-name
+                       temp-file
+                       (file-name-directory buffer-file-name))))
+    (list "perl" (list "-wc " local-file))))
+
+;;;; php-specific init-cleanup routines
+(defun flymake-proc-php-init ()
+  (let* ((temp-file   (flymake-proc-init-create-temp-buffer-copy
+                       'flymake-proc-create-temp-inplace))
+        (local-file  (file-relative-name
+                       temp-file
+                       (file-name-directory buffer-file-name))))
+    (list "php" (list "-f" local-file "-l"))))
+
+;;;; tex-specific init-cleanup routines
+(defun flymake-proc--get-tex-args (file-name)
+  ;;(list "latex" (list "-c-style-errors" file-name))
+  (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
+
+(defun flymake-proc-simple-tex-init ()
+  (flymake-proc--get-tex-args (flymake-proc-init-create-temp-buffer-copy 
'flymake-proc-create-temp-inplace)))
+
+;; Perhaps there should be a buffer-local variable flymake-master-file
+;; that people can set to override this stuff.  Could inherit from
+;; the similar AUCTeX variable.
+(defun flymake-proc-master-tex-init ()
+  (let* ((temp-master-file-name 
(flymake-proc--init-create-temp-source-and-master-buffer-copy
+                                 'flymake-proc-get-include-dirs-dot 
'flymake-proc-create-temp-inplace
+                                '("\\.tex\\'")
+                                "[ \t]*\\in\\(?:put\\|clude\\)[ 
\t]*{\\(.*%s\\)}")))
+    (when temp-master-file-name
+      (flymake-proc--get-tex-args temp-master-file-name))))
+
+(defun flymake-proc--get-include-dirs-dot (_base-dir)
+  '("."))
+
+;;;; xml-specific init-cleanup routines
+(defun flymake-proc-xml-init ()
+  (list flymake-proc-xml-program
+        (list "val" (flymake-proc-init-create-temp-buffer-copy
+                     'flymake-proc-create-temp-inplace))))
+
+
+;;;; Hook onto flymake-ui
+(add-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
+
+
+;;;;
+
+(progn
+  (define-obsolete-variable-alias 'flymake-compilation-prevents-syntax-check
+    'flymake-proc-compilation-prevents-syntax-check "26.1")
+  (define-obsolete-variable-alias 'flymake-xml-program
+    'flymake-proc-xml-program "26.1")
+  (define-obsolete-variable-alias 'flymake-master-file-dirs
+    'flymake-proc-master-file-dirs "26.1")
+  (define-obsolete-variable-alias 'flymake-master-file-count-limit
+    'flymake-proc-master-file-count-limit "26.1"
+    "Max number of master files to check.")
+  (define-obsolete-variable-alias 'flymake-allowed-file-name-masks
+    'flymake-proc-allowed-file-name-masks "26.1")
+  (define-obsolete-variable-alias 'flymake-check-file-limit
+    'flymake-proc-check-file-limit "26.1")
+  (define-obsolete-function-alias 
'flymake-reformat-err-line-patterns-from-compile-el
+    'flymake-proc-reformat-err-line-patterns-from-compile-el "26.1")
+  (define-obsolete-variable-alias 'flymake-err-line-patterns
+    'flymake-proc-err-line-patterns "26.1")
+  (define-obsolete-function-alias 'flymake-parse-line
+    'flymake-proc-parse-line "26.1")
+  (define-obsolete-function-alias 'flymake-get-include-dirs
+    'flymake-proc-get-include-dirs "26.1")
+  (define-obsolete-function-alias 'flymake-stop-all-syntax-checks
+    'flymake-proc-stop-all-syntax-checks "26.1")
+  (define-obsolete-function-alias 'flymake-compile
+    'flymake-proc-compile "26.1")
+  (define-obsolete-function-alias 'flymake-create-temp-inplace
+    'flymake-proc-create-temp-inplace "26.1")
+  (define-obsolete-function-alias 'flymake-create-temp-with-folder-structure
+    'flymake-proc-create-temp-with-folder-structure "26.1")
+  (define-obsolete-function-alias 'flymake-init-create-temp-buffer-copy
+    'flymake-proc-init-create-temp-buffer-copy "26.1")
+  (define-obsolete-function-alias 'flymake-simple-cleanup
+    'flymake-proc-simple-cleanup "26.1")
+  (define-obsolete-function-alias 'flymake-get-real-file-name
+    'flymake-proc-get-real-file-name "26.1")
+  (define-obsolete-function-alias 'flymake-master-cleanup
+    'flymake-proc-master-cleanup "26.1")
+  (define-obsolete-function-alias 'flymake-get-make-cmdline
+    'flymake-proc-get-make-cmdline "26.1")
+  (define-obsolete-function-alias 'flymake-get-ant-cmdline
+    'flymake-proc-get-ant-cmdline "26.1")
+  (define-obsolete-function-alias 'flymake-simple-make-init-impl
+    'flymake-proc-simple-make-init-impl "26.1")
+  (define-obsolete-function-alias 'flymake-simple-make-init
+    'flymake-proc-simple-make-init "26.1")
+  (define-obsolete-function-alias 'flymake-master-make-init
+    'flymake-proc-master-make-init "26.1")
+  (define-obsolete-function-alias 'flymake-find-make-buildfile
+    'flymake-proc--find-make-buildfile "26.1")
+  (define-obsolete-function-alias 'flymake-master-make-header-init
+    'flymake-proc-master-make-header-init "26.1")
+  (define-obsolete-function-alias 'flymake-simple-make-java-init
+    'flymake-proc-simple-make-java-init "26.1")
+  (define-obsolete-function-alias 'flymake-simple-ant-java-init
+    'flymake-proc-simple-ant-java-init "26.1")
+  (define-obsolete-function-alias 'flymake-simple-java-cleanup
+    'flymake-proc-simple-java-cleanup "26.1")
+  (define-obsolete-function-alias 'flymake-perl-init
+    'flymake-proc-perl-init "26.1")
+  (define-obsolete-function-alias 'flymake-php-init
+    'flymake-proc-php-init "26.1")
+  (define-obsolete-function-alias 'flymake-simple-tex-init
+    'flymake-proc-simple-tex-init "26.1")
+  (define-obsolete-function-alias 'flymake-master-tex-init
+    'flymake-proc-master-tex-init "26.1")
+  (define-obsolete-function-alias 'flymake-xml-init
+    'flymake-proc-xml-init "26.1"))
+
+
+
+(provide 'flymake-proc)
+;;; flymake-proc.el ends here
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 866116f..c1a15bf 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -1,4 +1,4 @@
-;;; flymake.el --- a universal on-the-fly syntax checker  -*- lexical-binding: 
t; -*-
+;;; flymake.el --- A universal on-the-fly syntax checker  -*- lexical-binding: 
t; -*-
 
 ;; Copyright (C) 2003-2017 Free Software Foundation, Inc.
 
@@ -20,22 +20,35 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
-;; Flymake is a minor Emacs mode performing on-the-fly syntax checks
-;; using the external syntax check tool (for C/C++ this is usually the
-;; compiler).
-
-;;; Bugs/todo:
-
-;; - Only uses "Makefile", not "makefile" or "GNUmakefile"
-;;   (from http://bugs.debian.org/337339).
-
+;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.
+;;
+;; Flymake collects diagnostic information for multiple sources,
+;; called backends, and visually annotates the relevant portions in
+;; the buffer.
+;;
+;; This file contains the UI for displaying and interacting with the
+;; results produced by these backends, as well as entry points for
+;; backends to hook on to.
+;;
+;; The main entry points are `flymake-mode' and `flymake-start'
+;;
+;; The docstrings of these variabless are relevant to understanding how
+;; Flymake works for both the user and the backend programmer:
+;;
+;; * `flymake-diagnostic-functions'
+;; * `flymake-diagnostic-types-alist'
+;;
 ;;; Code:
 
-(eval-when-compile (require 'cl-lib))
+(require 'cl-lib)
+(require 'thingatpt) ; end-of-thing
+(require 'warnings) ; warning-numeric-level, display-warning
+(require 'compile) ; for some faces
+(require 'subr-x) ; when-let*, if-let*, hash-table-keys, hash-table-values
 
 (defgroup flymake nil
   "Universal on-the-fly syntax checker."
@@ -43,7 +56,8 @@
   :link '(custom-manual "(flymake) Top")
   :group 'tools)
 
-(defcustom flymake-error-bitmap '(exclamation-mark error)
+(defcustom flymake-error-bitmap '(flymake-double-exclamation-mark
+                                  compilation-error)
   "Bitmap (a symbol) used in the fringe for indicating errors.
 The value may also be a list of two elements where the second
 element specifies the face for the bitmap.  For possible bitmap
@@ -51,14 +65,13 @@ symbols, see `fringe-bitmaps'.  See also 
`flymake-warning-bitmap'.
 
 The option `flymake-fringe-indicator-position' controls how and where
 this is used."
-  :group 'flymake
   :version "24.3"
   :type '(choice (symbol :tag "Bitmap")
                  (list :tag "Bitmap and face"
                        (symbol :tag "Bitmap")
                        (face :tag "Face"))))
 
-(defcustom flymake-warning-bitmap 'question-mark
+(defcustom flymake-warning-bitmap '(exclamation-mark compilation-warning)
   "Bitmap (a symbol) used in the fringe for indicating warnings.
 The value may also be a list of two elements where the second
 element specifies the face for the bitmap.  For possible bitmap
@@ -66,1179 +79,651 @@ symbols, see `fringe-bitmaps'.  See also 
`flymake-error-bitmap'.
 
 The option `flymake-fringe-indicator-position' controls how and where
 this is used."
-  :group 'flymake
   :version "24.3"
   :type '(choice (symbol :tag "Bitmap")
                  (list :tag "Bitmap and face"
                        (symbol :tag "Bitmap")
                        (face :tag "Face"))))
 
+(defcustom flymake-note-bitmap '(exclamation-mark compilation-info)
+  "Bitmap (a symbol) used in the fringe for indicating info notes.
+The value may also be a list of two elements where the second
+element specifies the face for the bitmap.  For possible bitmap
+symbols, see `fringe-bitmaps'.  See also `flymake-error-bitmap'.
+
+The option `flymake-fringe-indicator-position' controls how and where
+this is used."
+  :version "26.1"
+  :type '(choice (symbol :tag "Bitmap")
+                 (list :tag "Bitmap and face"
+                       (symbol :tag "Bitmap")
+                       (face :tag "Face"))))
+
 (defcustom flymake-fringe-indicator-position 'left-fringe
-  "The position to put flymake fringe indicator.
+  "The position to put Flymake fringe indicator.
 The value can be nil (do not use indicators), `left-fringe' or `right-fringe'.
 See `flymake-error-bitmap' and `flymake-warning-bitmap'."
-  :group 'flymake
   :version "24.3"
   :type '(choice (const left-fringe)
                 (const right-fringe)
                 (const :tag "No fringe indicators" nil)))
 
-(defcustom flymake-compilation-prevents-syntax-check t
-  "If non-nil, don't start syntax check if compilation is running."
-  :group 'flymake
-  :type 'boolean)
-
 (defcustom flymake-start-syntax-check-on-newline t
   "Start syntax check if newline char was added/removed from the buffer."
-  :group 'flymake
   :type 'boolean)
 
 (defcustom flymake-no-changes-timeout 0.5
-  "Time to wait after last change before starting compilation."
-  :group 'flymake
+  "Time to wait after last change before automatically checking buffer.
+If nil, never start checking buffer automatically like this."
   :type 'number)
 
 (defcustom flymake-gui-warnings-enabled t
   "Enables/disables GUI warnings."
-  :group 'flymake
   :type 'boolean)
 (make-obsolete-variable 'flymake-gui-warnings-enabled
                        "it no longer has any effect." "26.1")
 
 (defcustom flymake-start-syntax-check-on-find-file t
   "Start syntax check on find file."
-  :group 'flymake
   :type 'boolean)
 
 (defcustom flymake-log-level -1
-  "Logging level, only messages with level lower or equal will be logged.
--1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
-  :group 'flymake
+  "Obsolete and ignored variable."
   :type 'integer)
+(make-obsolete-variable 'flymake-log-level
+                       "it is superseded by `warning-minimum-log-level.'"
+                        "26.1")
 
-(defcustom flymake-xml-program
-  (if (executable-find "xmlstarlet") "xmlstarlet" "xml")
-  "Program to use for XML validation."
-  :type 'file
-  :group 'flymake
-  :version "24.4")
-
-(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest")
-  "Dirs where to look for master files."
-  :group 'flymake
-  :type '(repeat (string)))
-
-(defcustom flymake-master-file-count-limit 32
-  "Max number of master files to check."
-  :group 'flymake
-  :type 'integer)
+(defcustom flymake-wrap-around t
+  "If non-nil, moving to errors wraps around buffer boundaries."
+  :type 'boolean)
 
-(defcustom flymake-allowed-file-name-masks
-  '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init)
-    ("\\.xml\\'" flymake-xml-init)
-    ("\\.html?\\'" flymake-xml-init)
-    ("\\.cs\\'" flymake-simple-make-init)
-    ("\\.p[ml]\\'" flymake-perl-init)
-    ("\\.php[345]?\\'" flymake-php-init)
-    ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup)
-    ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup)
-    ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup)
-    ("\\.tex\\'" flymake-simple-tex-init)
-    ("\\.idl\\'" flymake-simple-make-init)
-    ;; ("\\.cpp\\'" 1)
-    ;; ("\\.java\\'" 3)
-    ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'")
-    ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 
2))
-    ;; ("\\.idl\\'" 1)
-    ;; ("\\.odl\\'" 1)
-    ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'")
-    ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
-    ;; ("\\.tex\\'" 1)
-    )
-  "Files syntax checking is allowed for.
-This is an alist with elements of the form:
-  REGEXP INIT [CLEANUP [NAME]]
-REGEXP is a regular expression that matches a file name.
-INIT is the init function to use, missing means disable `flymake-mode'.
-CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'.
-NAME is the file name function to use, default `flymake-get-real-file-name'."
-  :group 'flymake
-  :type '(alist :key-type (regexp :tag "File regexp")
-                :value-type
-                (list :tag "Handler functions"
-                      (choice :tag "Init function"
-                              (const :tag "disable" nil)
-                              function)
-                      (choice :tag "Cleanup function"
-                              (const :tag "flymake-simple-cleanup" nil)
-                              function)
-                      (choice :tag "Name function"
-                              (const :tag "flymake-get-real-file-name" nil)
-                              function))))
-
-(defvar-local flymake-is-running nil
-  "If t, flymake syntax check process is running for the current buffer.")
+(define-fringe-bitmap 'flymake-double-exclamation-mark
+  (vector #b00000000
+          #b00000000
+          #b00000000
+          #b00000000
+          #b01100110
+          #b01100110
+          #b01100110
+          #b01100110
+          #b01100110
+          #b01100110
+          #b01100110
+          #b01100110
+          #b00000000
+          #b01100110
+          #b00000000
+          #b00000000
+          #b00000000))
 
 (defvar-local flymake-timer nil
   "Timer for starting syntax check.")
 
-(defvar-local flymake-last-change-time nil
-  "Time of last buffer change.")
-
 (defvar-local flymake-check-start-time nil
   "Time at which syntax check was started.")
 
-(defvar-local flymake-check-was-interrupted nil
-  "Non-nil if syntax check was killed by `flymake-compile'.")
-
-(defvar-local flymake-err-info nil
-  "Sorted list of line numbers and lists of err info in the form (file, 
err-text).")
-
-(defvar-local flymake-new-err-info nil
-  "Same as `flymake-err-info', effective when a syntax check is in progress.")
-
-(defun flymake-log (level text &rest args)
-  "Log a message at level LEVEL.
-If LEVEL is higher than `flymake-log-level', the message is
-ignored.  Otherwise, it is printed using `message'.
-TEXT is a format control string, and the remaining arguments ARGS
-are the string substitutions (see the function `format')."
-  (if (<= level flymake-log-level)
-      (let* ((msg (apply #'format-message text args)))
-       (message "%s" msg))))
-
-(defun flymake-ins-after (list pos val)
-  "Insert VAL into LIST after position POS.
-POS counts from zero."
-  (let ((tmp (copy-sequence list)))
-    (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp)))
-    tmp))
-
-(defun flymake-set-at (list pos val)
-  "Set VAL at position POS in LIST.
-POS counts from zero."
-  (let ((tmp (copy-sequence list)))
-    (setcar (nthcdr pos tmp) val)
-    tmp))
-
-(defvar flymake-processes nil
-  "List of currently active flymake processes.")
-
-(defvar-local flymake-output-residual nil)
-
-(defun flymake-get-file-name-mode-and-masks (file-name)
-  "Return the corresponding entry from `flymake-allowed-file-name-masks'."
-  (unless (stringp file-name)
-    (error "Invalid file-name"))
-  (let ((fnm flymake-allowed-file-name-masks)
-       (mode-and-masks nil))
-    (while (and (not mode-and-masks) fnm)
-      (let ((item (pop fnm)))
-        (when (string-match (car item) file-name)
-         (setq mode-and-masks item)))) ; (cdr item) may be nil
-    (setq mode-and-masks (cdr mode-and-masks))
-    (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
-    mode-and-masks))
-
-(defun flymake-can-syntax-check-file (file-name)
-  "Determine whether we can syntax check FILE-NAME.
-Return nil if we cannot, non-nil if we can."
-  (if (flymake-get-init-function file-name) t nil))
-
-(defun flymake-get-init-function (file-name)
-  "Return init function to be used for the file."
-  (let* ((init-f  (nth 0 (flymake-get-file-name-mode-and-masks file-name))))
-    ;;(flymake-log 0 "calling %s" init-f)
-    ;;(funcall init-f (current-buffer))
-    init-f))
-
-(defun flymake-get-cleanup-function (file-name)
-  "Return cleanup function to be used for the file."
-  (or (nth 1 (flymake-get-file-name-mode-and-masks file-name))
-      'flymake-simple-cleanup))
-
-(defun flymake-get-real-file-name-function (file-name)
-  (or (nth 2 (flymake-get-file-name-mode-and-masks file-name))
-      'flymake-get-real-file-name))
-
-(defvar flymake-find-buildfile-cache (make-hash-table :test #'equal))
-
-(defun flymake-get-buildfile-from-cache (dir-name)
-  "Look up DIR-NAME in cache and return its associated value.
-If DIR-NAME is not found, return nil."
-  (gethash dir-name flymake-find-buildfile-cache))
-
-(defun flymake-add-buildfile-to-cache (dir-name buildfile)
-  "Associate DIR-NAME with BUILDFILE in the buildfile cache."
-  (puthash dir-name buildfile flymake-find-buildfile-cache))
-
-(defun flymake-clear-buildfile-cache ()
-  "Clear the buildfile cache."
-  (clrhash flymake-find-buildfile-cache))
-
-(defun flymake-find-buildfile (buildfile-name source-dir-name)
-  "Find buildfile starting from current directory.
-Buildfile includes Makefile, build.xml etc.
-Return its file name if found, or nil if not found."
-  (or (flymake-get-buildfile-from-cache source-dir-name)
-      (let* ((file (locate-dominating-file source-dir-name buildfile-name)))
-        (if file
-            (progn
-              (flymake-log 3 "found buildfile at %s" file)
-              (flymake-add-buildfile-to-cache source-dir-name file)
-              file)
-          (progn
-            (flymake-log 3 "buildfile for %s not found" source-dir-name)
-            nil)))))
-
-(defun flymake-fix-file-name (name)
-  "Replace all occurrences of `\\' with `/'."
-  (when name
-    (setq name (expand-file-name name))
-    (setq name (abbreviate-file-name name))
-    (setq name (directory-file-name name))
-    name))
-
-(defun flymake-same-files (file-name-one file-name-two)
-  "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
-Return t if so, nil if not."
-  (equal (flymake-fix-file-name file-name-one)
-        (flymake-fix-file-name file-name-two)))
-
-;; This is bound dynamically to pass a parameter to a sort predicate below
-(defvar flymake-included-file-name)
-
-(defun flymake-find-possible-master-files (file-name master-file-dirs masks)
-  "Find (by name and location) all possible master files.
-
-Name is specified by FILE-NAME and location is specified by
-MASTER-FILE-DIRS.  Master files include .cpp and .c for .h.
-Files are searched for starting from the .h directory and max
-max-level parent dirs.  File contents are not checked."
-  (let* ((dirs master-file-dirs)
-        (files  nil)
-        (done   nil))
-
-    (while (and (not done) dirs)
-      (let* ((dir (expand-file-name (car dirs) (file-name-directory 
file-name)))
-            (masks masks))
-       (while (and (file-exists-p dir) (not done) masks)
-         (let* ((mask        (car masks))
-                (dir-files   (directory-files dir t mask)))
-
-           (flymake-log 3 "dir %s, %d file(s) for mask %s"
-                        dir (length dir-files) mask)
-           (while (and (not done) dir-files)
-             (when (not (file-directory-p (car dir-files)))
-               (setq files (cons (car dir-files) files))
-               (when (>= (length files) flymake-master-file-count-limit)
-                 (flymake-log 3 "master file count limit (%d) reached" 
flymake-master-file-count-limit)
-                 (setq done t)))
-             (setq dir-files (cdr dir-files))))
-         (setq masks (cdr masks))))
-      (setq dirs (cdr dirs)))
-    (when files
-      (let ((flymake-included-file-name (file-name-nondirectory file-name)))
-       (setq files (sort files 'flymake-master-file-compare))))
-    (flymake-log 3 "found %d possible master file(s)" (length files))
-    files))
-
-(defun flymake-master-file-compare (file-one file-two)
-  "Compare two files specified by FILE-ONE and FILE-TWO.
-This function is used in sort to move most possible file names
-to the beginning of the list (File.h -> File.cpp moved to top)."
-  (and (equal (file-name-sans-extension flymake-included-file-name)
-             (file-name-base file-one))
-       (not (equal file-one file-two))))
-
-(defvar flymake-check-file-limit 8192
-  "Maximum number of chars to look at when checking possible master file.
-Nil means search the entire file.")
-
-(defun flymake-check-patch-master-file-buffer
-    (master-file-temp-buffer
-     master-file-name patched-master-file-name
-     source-file-name patched-source-file-name
-     include-dirs regexp)
-  "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
-If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
-instead of SOURCE-FILE-NAME.
-
-For example, foo.cpp is a master file if it includes foo.h.
-
-When a buffer for MASTER-FILE-NAME exists, use it as a source
-instead of reading master file from disk."
-  (let* ((source-file-nondir (file-name-nondirectory source-file-name))
-         (source-file-extension (file-name-extension source-file-nondir))
-         (source-file-nonext (file-name-sans-extension source-file-nondir))
-         (found                     nil)
-        (inc-name                  nil)
-        (search-limit              flymake-check-file-limit))
-    (setq regexp
-          (format regexp       ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\""
-                  ;; Hack for tex files, where \include often excludes .tex.
-                  ;; Maybe this is safe generally.
-                  (if (and (> (length source-file-extension) 1)
-                           (string-equal source-file-extension "tex"))
-                      (format "%s\\(?:\\.%s\\)?"
-                              (regexp-quote source-file-nonext)
-                              (regexp-quote source-file-extension))
-                    (regexp-quote source-file-nondir))))
-    (unwind-protect
-        (with-current-buffer master-file-temp-buffer
-          (if (or (not search-limit)
-                  (> search-limit (point-max)))
-              (setq search-limit (point-max)))
-          (flymake-log 3 "checking %s against regexp %s"
-                       master-file-name regexp)
-          (goto-char (point-min))
-          (while (and (< (point) search-limit)
-                      (re-search-forward regexp search-limit t))
-            (let ((match-beg   (match-beginning 1))
-                  (match-end   (match-end 1)))
-
-              (flymake-log 3 "found possible match for %s" source-file-nondir)
-              (setq inc-name (match-string 1))
-              (and (> (length source-file-extension) 1)
-                   (string-equal source-file-extension "tex")
-                   (not (string-match (format "\\.%s\\'" source-file-extension)
-                                      inc-name))
-                   (setq inc-name (concat inc-name "." source-file-extension)))
-              (when (eq t (compare-strings
-                           source-file-nondir nil nil
-                           inc-name (- (length inc-name)
-                                       (length source-file-nondir)) nil))
-                (flymake-log 3 "inc-name=%s" inc-name)
-                (when (flymake-check-include source-file-name inc-name
-                                             include-dirs)
-                  (setq found t)
-                  ;;  replace-match is not used here as it fails in
-                  ;; XEmacs with 'last match not a buffer' error as
-                  ;; check-includes calls replace-in-string
-                  (flymake-replace-region
-                   match-beg match-end
-                   (file-name-nondirectory patched-source-file-name))))
-              (forward-line 1)))
-          (when found
-            (flymake-save-buffer-in-file patched-master-file-name)))
-      ;;+(flymake-log 3 "killing buffer %s"
-      ;;                (buffer-name master-file-temp-buffer))
-      (kill-buffer master-file-temp-buffer))
-    ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found)
-    (when found
-      (flymake-log 2 "found master file %s" master-file-name))
-    found))
-
-;;; XXX: remove
-(defun flymake-replace-region (beg end rep)
-  "Replace text in BUFFER in region (BEG END) with REP."
-  (save-excursion
-    (goto-char end)
-    ;; Insert before deleting, so as to better preserve markers's positions.
-    (insert rep)
-    (delete-region beg end)))
-
-(defun flymake-read-file-to-temp-buffer (file-name)
-  "Insert contents of FILE-NAME into newly created temp buffer."
-  (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat 
"flymake:" (file-name-nondirectory file-name))))))
-    (with-current-buffer temp-buffer
-      (insert-file-contents file-name))
-    temp-buffer))
-
-(defun flymake-copy-buffer-to-temp-buffer (buffer)
-  "Copy contents of BUFFER into newly created temp buffer."
-  (with-current-buffer
-      (get-buffer-create (generate-new-buffer-name
-                          (concat "flymake:" (buffer-name buffer))))
-    (insert-buffer-substring buffer)
-    (current-buffer)))
-
-(defun flymake-check-include (source-file-name inc-name include-dirs)
-  "Check if SOURCE-FILE-NAME can be found in include path.
-Return t if it can be found via include path using INC-NAME."
-  (if (file-name-absolute-p inc-name)
-      (flymake-same-files source-file-name inc-name)
-    (while (and include-dirs
-                (not (flymake-same-files
-                      source-file-name
-                      (concat (file-name-directory source-file-name)
-                              "/" (car include-dirs)
-                              "/" inc-name))))
-      (setq include-dirs (cdr include-dirs)))
-    include-dirs))
-
-(defun flymake-find-buffer-for-file (file-name)
-  "Check if there exists a buffer visiting FILE-NAME.
-Return t if so, nil if not."
-  (let ((buffer-name (get-file-buffer file-name)))
-    (if buffer-name
-       (get-buffer buffer-name))))
-
-(defun flymake-create-master-file (source-file-name patched-source-file-name 
get-incl-dirs-f create-temp-f masks include-regexp)
-  "Save SOURCE-FILE-NAME with a different name.
-Find master file, patch and save it."
-  (let* ((possible-master-files     (flymake-find-possible-master-files 
source-file-name flymake-master-file-dirs masks))
-        (master-file-count         (length possible-master-files))
-        (idx                       0)
-        (temp-buffer               nil)
-        (master-file-name          nil)
-        (patched-master-file-name  nil)
-        (found                     nil))
-
-    (while (and (not found) (< idx master-file-count))
-      (setq master-file-name (nth idx possible-master-files))
-      (setq patched-master-file-name (funcall create-temp-f master-file-name 
"flymake_master"))
-      (if (flymake-find-buffer-for-file master-file-name)
-         (setq temp-buffer (flymake-copy-buffer-to-temp-buffer 
(flymake-find-buffer-for-file master-file-name)))
-       (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)))
-      (setq found
-           (flymake-check-patch-master-file-buffer
-            temp-buffer
-            master-file-name
-            patched-master-file-name
-            source-file-name
-            patched-source-file-name
-            (funcall get-incl-dirs-f (file-name-directory master-file-name))
-            include-regexp))
-      (setq idx (1+ idx)))
-    (if found
-       (list master-file-name patched-master-file-name)
-      (progn
-       (flymake-log 3 "none of %d master file(s) checked includes %s" 
master-file-count
-                    (file-name-nondirectory source-file-name))
-       nil))))
-
-(defun flymake-save-buffer-in-file (file-name)
-  "Save the entire buffer contents into file FILE-NAME.
-Create parent directories as needed."
-  (make-directory (file-name-directory file-name) 1)
-  (write-region nil nil file-name nil 566)
-  (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name))
-
-(defun flymake-process-filter (process output)
-  "Parse OUTPUT and highlight error lines.
-It's flymake process filter."
-  (let ((source-buffer (process-buffer process)))
-
-    (flymake-log 3 "received %d byte(s) of output from process %d"
-                 (length output) (process-id process))
-    (when (buffer-live-p source-buffer)
-      (with-current-buffer source-buffer
-        (flymake-parse-output-and-residual output)))))
-
-(defun flymake-process-sentinel (process _event)
-  "Sentinel for syntax check buffers."
-  (when (memq (process-status process) '(signal exit))
-    (let* ((exit-status       (process-exit-status process))
-           (command           (process-command process))
-           (source-buffer     (process-buffer process))
-           (cleanup-f         (flymake-get-cleanup-function (buffer-file-name 
source-buffer))))
-
-      (flymake-log 2 "process %d exited with code %d"
-                   (process-id process) exit-status)
-      (condition-case err
-          (progn
-            (flymake-log 3 "cleaning up using %s" cleanup-f)
-            (when (buffer-live-p source-buffer)
-              (with-current-buffer source-buffer
-                (funcall cleanup-f)))
-
-            (delete-process process)
-            (setq flymake-processes (delq process flymake-processes))
-
-            (when (buffer-live-p source-buffer)
-              (with-current-buffer source-buffer
-
-                (flymake-parse-residual)
-                (flymake-post-syntax-check exit-status command)
-                (setq flymake-is-running nil))))
-        (error
-         (let ((err-str (format "Error in process sentinel for buffer %s: %s"
-                                source-buffer (error-message-string err))))
-           (flymake-log 0 err-str)
-           (with-current-buffer source-buffer
-             (setq flymake-is-running nil))))))))
-
-(defun flymake-post-syntax-check (exit-status command)
+(defun flymake--log-1 (level sublog msg &rest args)
+  "Do actual work for `flymake-log'."
+  (let (;; never popup the log buffer
+        (warning-minimum-level :emergency)
+        (warning-type-format
+         (format " [%s %s]"
+                 (or sublog 'flymake)
+                 (current-buffer))))
+    (display-warning (list 'flymake sublog)
+                     (apply #'format-message msg args)
+                     (if (numberp level)
+                         (or (nth level
+                                  '(:emergency :error :warning :debug :debug) )
+                             :error)
+                       level)
+                     "*Flymake log*")))
+
+;;;###autoload
+(defmacro flymake-log (level msg &rest args)
+  "Log, at level LEVEL, the message MSG formatted with ARGS.
+LEVEL is passed to `display-warning', which is used to display
+the warning.  If this form is included in a byte-compiled file,
+the generated warning contains an indication of the file that
+generated it."
+  (let* ((compile-file (and (boundp 'byte-compile-current-file)
+                            (symbol-value 'byte-compile-current-file)))
+         (sublog (if (and
+                      compile-file
+                      (not load-file-name))
+                     (intern
+                      (file-name-nondirectory
+                       (file-name-sans-extension compile-file))))))
+    `(flymake--log-1 ,level ',sublog ,msg ,@args)))
+
+(defun flymake-error (text &rest args)
+  "Format TEXT with ARGS and signal an error for flymake."
+  (let ((msg (apply #'format-message text args)))
+    (flymake-log :error msg)
+    (error (concat "[Flymake] " msg))))
+
+(cl-defstruct (flymake--diag
+               (:constructor flymake--diag-make))
+  buffer beg end type text backend)
+
+;;;###autoload
+(defun flymake-make-diagnostic (buffer
+                                beg
+                                end
+                                type
+                                text)
+  "Make a Flymake diagnostic for BUFFER's region from BEG to END.
+TYPE is a key to `flymake-diagnostic-types-alist' and TEXT is a
+description of the problem detected in this region."
+  (flymake--diag-make :buffer buffer :beg beg :end end :type type :text text))
+
+(defun flymake-ler-make-ler (file line type text &optional full-file)
+  (let* ((file (or full-file file))
+         (buf (find-buffer-visiting file)))
+    (unless buf (flymake-error "No buffer visiting %s" file))
+    (pcase-let* ((`(,beg . ,end)
+                  (with-current-buffer buf
+                    (flymake-diag-region line nil))))
+      (flymake-make-diagnostic buf beg end type text))))
+
+(make-obsolete 'flymake-ler-make-ler 'flymake-make-diagnostic "26.1")
+
+(cl-defun flymake--overlays (&key beg end filter compare key)
+  "Get flymake-related overlays.
+If BEG is non-nil and END is nil, consider only `overlays-at'
+BEG. Otherwise consider `overlays-in' the region comprised by BEG
+and END, defaulting to the whole buffer.  Remove all that do not
+verify FILTER, a function, and sort them by COMPARE (using KEY)."
   (save-restriction
     (widen)
-    (setq flymake-err-info flymake-new-err-info)
-    (setq flymake-new-err-info nil)
-    (setq flymake-err-info
-          (flymake-fix-line-numbers
-           flymake-err-info 1 (count-lines (point-min) (point-max))))
-    (flymake-delete-own-overlays)
-    (flymake-highlight-err-lines flymake-err-info)
-    (let (err-count warn-count)
-      (setq err-count (flymake-get-err-count flymake-err-info "e"))
-      (setq warn-count  (flymake-get-err-count flymake-err-info "w"))
-      (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)"
-                   (buffer-name) err-count warn-count
-                   (- (float-time) flymake-check-start-time))
-      (setq flymake-check-start-time nil)
-
-      (if (and (equal 0 err-count) (equal 0 warn-count))
-          (if (equal 0 exit-status)
-              (flymake-report-status "" "") ; PASSED
-            (if (not flymake-check-was-interrupted)
-                (flymake-report-fatal-status "CFGERR"
-                                             (format "Configuration error has 
occurred while running %s" command))
-              (flymake-report-status nil ""))) ; "STOPPED"
-        (flymake-report-status (format "%d/%d" err-count warn-count) "")))))
-
-(defun flymake-parse-output-and-residual (output)
-  "Split OUTPUT into lines, merge in residual if necessary."
-  (let* ((buffer-residual     flymake-output-residual)
-         (total-output        (if buffer-residual (concat buffer-residual 
output) output))
-         (lines-and-residual  (flymake-split-output total-output))
-         (lines               (nth 0 lines-and-residual))
-         (new-residual        (nth 1 lines-and-residual)))
-    (setq flymake-output-residual new-residual)
-    (setq flymake-new-err-info
-          (flymake-parse-err-lines
-           flymake-new-err-info lines))))
-
-(defun flymake-parse-residual ()
-  "Parse residual if it's non empty."
-  (when flymake-output-residual
-    (setq flymake-new-err-info
-          (flymake-parse-err-lines
-           flymake-new-err-info
-           (list flymake-output-residual)))
-    (setq flymake-output-residual nil)))
-
-(defun flymake-er-make-er (line-no line-err-info-list)
-  (list line-no line-err-info-list))
-
-(defun flymake-er-get-line (err-info)
-  (nth 0 err-info))
-
-(defun flymake-er-get-line-err-info-list (err-info)
-  (nth 1 err-info))
-
-(cl-defstruct (flymake-ler
-               (:constructor nil)
-               (:constructor flymake-ler-make-ler (file line type text 
&optional full-file)))
-  file line type text full-file)
-
-(defun flymake-ler-set-file (line-err-info file)
-  (flymake-ler-make-ler file
-                       (flymake-ler-line line-err-info)
-                       (flymake-ler-type line-err-info)
-                       (flymake-ler-text line-err-info)
-                       (flymake-ler-full-file line-err-info)))
-
-(defun flymake-ler-set-full-file (line-err-info full-file)
-  (flymake-ler-make-ler (flymake-ler-file line-err-info)
-                       (flymake-ler-line line-err-info)
-                       (flymake-ler-type line-err-info)
-                       (flymake-ler-text line-err-info)
-                       full-file))
-
-(defun flymake-ler-set-line (line-err-info line)
-  (flymake-ler-make-ler (flymake-ler-file line-err-info)
-                       line
-                       (flymake-ler-type line-err-info)
-                       (flymake-ler-text line-err-info)
-                       (flymake-ler-full-file line-err-info)))
-
-(defun flymake-get-line-err-count (line-err-info-list type)
-  "Return number of errors of specified TYPE.
-Value of TYPE is either \"e\" or \"w\"."
-  (let* ((idx        0)
-        (count      (length line-err-info-list))
-        (err-count  0))
-
-    (while (< idx count)
-      (when (equal type (flymake-ler-type (nth idx line-err-info-list)))
-       (setq err-count (1+ err-count)))
-      (setq idx (1+ idx)))
-    err-count))
-
-(defun flymake-get-err-count (err-info-list type)
-  "Return number of errors of specified TYPE for ERR-INFO-LIST."
-  (let* ((idx        0)
-        (count      (length err-info-list))
-        (err-count  0))
-    (while (< idx count)
-      (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx 
err-info-list)) type)))
-      (setq idx (1+ idx)))
-    err-count))
-
-(defun flymake-fix-line-numbers (err-info-list min-line max-line)
-  "Replace line numbers with fixed value.
-If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE.
-If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE.
-The reason for this fix is because some compilers might report
-line number outside the file being compiled."
-  (let* ((count     (length err-info-list))
-        (err-info  nil)
-        (line      0))
-    (while (> count 0)
-      (setq err-info (nth (1- count) err-info-list))
-      (setq line (flymake-er-get-line err-info))
-      (when (or (< line min-line) (> line max-line))
-       (setq line (if (< line min-line) min-line max-line))
-       (setq err-info-list (flymake-set-at err-info-list (1- count)
-                                           (flymake-er-make-er line
-                                                               
(flymake-er-get-line-err-info-list err-info)))))
-      (setq count (1- count))))
-  err-info-list)
-
-(defun flymake-highlight-err-lines (err-info-list)
-  "Highlight error lines in BUFFER using info from ERR-INFO-LIST."
-  (save-excursion
-    (dolist (err err-info-list)
-      (flymake-highlight-line (car err) (nth 1 err)))))
-
-(defun flymake-overlay-p (ov)
-  "Determine whether overlay OV was created by flymake."
-  (and (overlayp ov) (overlay-get ov 'flymake-overlay)))
-
-(defun flymake-make-overlay (beg end tooltip-text face bitmap)
-  "Allocate a flymake overlay in range BEG and END."
-  (when (not (flymake-region-has-flymake-overlays beg end))
-    (let ((ov (make-overlay beg end nil t))
-         (fringe (and flymake-fringe-indicator-position
-                      (propertize "!" 'display
-                                  (cons flymake-fringe-indicator-position
-                                        (if (listp bitmap)
-                                            bitmap
-                                          (list bitmap)))))))
-      (overlay-put ov 'face           face)
-      (overlay-put ov 'help-echo      tooltip-text)
-      (overlay-put ov 'flymake-overlay  t)
-      (overlay-put ov 'priority 100)
-      (overlay-put ov 'evaporate t)
-      (overlay-put ov 'before-string fringe)
-      ;;+(flymake-log 3 "created overlay %s" ov)
-      ov)
-    (flymake-log 3 "created an overlay at (%d-%d)" beg end)))
-
-(defun flymake-delete-own-overlays ()
-  "Delete all flymake overlays in BUFFER."
-  (dolist (ol (overlays-in (point-min) (point-max)))
-    (when (flymake-overlay-p ol)
-      (delete-overlay ol)
-      ;;+(flymake-log 3 "deleted overlay %s" ol)
-      )))
-
-(defun flymake-region-has-flymake-overlays (beg end)
-  "Check if region specified by BEG and END has overlay.
-Return t if it has at least one flymake overlay, nil if no overlay."
-  (let ((ov                  (overlays-in beg end))
-       (has-flymake-overlays  nil))
-    (while (consp ov)
-      (when (flymake-overlay-p (car ov))
-       (setq has-flymake-overlays t))
-      (setq ov (cdr ov)))
-    has-flymake-overlays))
-
-(defface flymake-errline
+    (let ((ovs (cl-remove-if-not
+                (lambda (ov)
+                  (and (overlay-get ov 'flymake)
+                       (or (not filter)
+                           (funcall filter ov))))
+                (if (and beg (null end))
+                    (overlays-at beg t)
+                  (overlays-in (or beg (point-min))
+                               (or end (point-max)))))))
+      (if compare
+          (cl-sort ovs compare :key (or key
+                                        #'identity))
+        ovs))))
+
+(defun flymake-delete-own-overlays (&optional filter)
+  "Delete all Flymake overlays in BUFFER."
+  (mapc #'delete-overlay (flymake--overlays :filter filter)))
+
+(defface flymake-error
   '((((supports :underline (:style wave)))
      :underline (:style wave :color "Red1"))
     (t
      :inherit error))
-  "Face used for marking error lines."
-  :version "24.4"
-  :group 'flymake)
+  "Face used for marking error regions."
+  :version "24.4")
 
-(defface flymake-warnline
+(defface flymake-warning
   '((((supports :underline (:style wave)))
-     :underline (:style wave :color "DarkOrange"))
+     :underline (:style wave :color "deep sky blue"))
     (t
      :inherit warning))
-  "Face used for marking warning lines."
-  :version "24.4"
-  :group 'flymake)
-
-(defun flymake-highlight-line (line-no line-err-info-list)
-  "Highlight line LINE-NO in current buffer.
-Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting."
-  (goto-char (point-min))
-  (forward-line (1- line-no))
-  (pcase-let* ((beg (progn (back-to-indentation) (point)))
-               (end (progn
-                      (end-of-line)
-                      (skip-chars-backward " \t\f\t\n" beg)
-                      (if (eq (point) beg)
-                          (line-beginning-position 2)
-                        (point))))
-               (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list 
"\n"))
-               (`(,face ,bitmap)
-                (if (> (flymake-get-line-err-count line-err-info-list "e") 0)
-                    (list 'flymake-errline flymake-error-bitmap)
-                  (list 'flymake-warnline flymake-warning-bitmap))))
-    (flymake-make-overlay beg end tooltip-text face bitmap)))
-
-(defun flymake-parse-err-lines (err-info-list lines)
-  "Parse err LINES, store info in ERR-INFO-LIST."
-  (let* ((count              (length lines))
-        (idx                0)
-        (line-err-info      nil)
-        (real-file-name     nil)
-        (source-file-name   buffer-file-name)
-        (get-real-file-name-f (flymake-get-real-file-name-function 
source-file-name)))
-
-    (while (< idx count)
-      (setq line-err-info (flymake-parse-line (nth idx lines)))
-      (when line-err-info
-       (setq real-file-name (funcall get-real-file-name-f
-                                      (flymake-ler-file line-err-info)))
-       (setq line-err-info (flymake-ler-set-full-file line-err-info 
real-file-name))
-
-       (when (flymake-same-files real-file-name source-file-name)
-         (setq line-err-info (flymake-ler-set-file line-err-info nil))
-         (setq err-info-list (flymake-add-err-info err-info-list 
line-err-info))))
-      (flymake-log 3 "parsed `%s', %s line-err-info" (nth idx lines) (if 
line-err-info "got" "no"))
-      (setq idx (1+ idx)))
-    err-info-list))
-
-(defun flymake-split-output (output)
-  "Split OUTPUT into lines.
-Return last one as residual if it does not end with newline char.
-Returns ((LINES) RESIDUAL)."
-  (when (and output (> (length output) 0))
-    (let* ((lines (split-string output "[\n\r]+" t))
-          (complete (equal "\n" (char-to-string (aref output (1- (length 
output))))))
-          (residual nil))
-      (when (not complete)
-       (setq residual (car (last lines)))
-       (setq lines (butlast lines)))
-      (list lines residual))))
-
-(defun flymake-reformat-err-line-patterns-from-compile-el (original-list)
-  "Grab error line patterns from ORIGINAL-LIST in compile.el format.
-Convert it to flymake internal format."
-  (let* ((converted-list '()))
-    (dolist (item original-list)
-      (setq item (cdr item))
-      (let ((regexp (nth 0 item))
-           (file (nth 1 item))
-           (line (nth 2 item))
-           (col (nth 3 item)))
-       (if (consp file)        (setq file (car file)))
-       (if (consp line)        (setq line (car line)))
-       (if (consp col) (setq col (car col)))
-
-       (when (not (functionp line))
-         (setq converted-list (cons (list regexp file line col) 
converted-list)))))
-    converted-list))
-
-(require 'compile)
-
-(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx 
(optional) text-idx(optional), match-end to end of string is error text
-  (append
-   '(
-     ;; MS Visual C++ 6.0
-     ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : 
\\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
-      1 3 nil 4)
-     ;; jikes
-     ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: 
\\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
-      1 3 nil 4)
-     ;; MS midl
-     ("midl[ ]*:[ ]*\\(command line error .*\\)"
-      nil nil nil 1)
-     ;; MS C#
-     ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): 
\\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
-      1 3 nil 4)
-     ;; perl
-     ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
-     ;; PHP
-     ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 
2 3 nil 1)
-     ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on 
input line \\([0-9]+\\)" 20 3 nil 1)
-     ;; ant/javac.  Note this also matches gcc warnings!
-     (" *\\(\\[javac\\] 
*\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::[0-9]+\\)?:[ 
\t\n]*\\(.+\\)"
-      2 4 nil 5))
-   ;; compilation-error-regexp-alist)
-   (flymake-reformat-err-line-patterns-from-compile-el 
compilation-error-regexp-alist-alist))
-  "Patterns for matching error/warning lines.  Each pattern has the form
-\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX).
-Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns
-from compile.el")
-
-(define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate 
"24.4")
-(defvar flymake-warning-predicate "^[wW]arning"
-  "Predicate matching against error text to detect a warning.
-Takes a single argument, the error's text and should return non-nil
-if it's a warning.
-Instead of a function, it can also be a regular expression.")
-
-(defun flymake-parse-line (line)
-  "Parse LINE to see if it is an error or warning.
-Return its components if so, nil otherwise."
-  (let ((raw-file-name nil)
-       (line-no 0)
-       (err-type "e")
-       (err-text nil)
-       (patterns flymake-err-line-patterns)
-       (matched nil))
-    (while (and patterns (not matched))
-      (when (string-match (car (car patterns)) line)
-       (let* ((file-idx (nth 1 (car patterns)))
-              (line-idx (nth 2 (car patterns))))
-
-         (setq raw-file-name (if file-idx (match-string file-idx line) nil))
-         (setq line-no       (if line-idx (string-to-number
-                                            (match-string line-idx line)) 0))
-         (setq err-text      (if (> (length (car patterns)) 4)
-                                 (match-string (nth 4 (car patterns)) line)
-                               (flymake-patch-err-text
-                                 (substring line (match-end 0)))))
-         (if (null err-text)
-              (setq err-text "<no error text>")
-            (when (cond ((stringp flymake-warning-predicate)
-                         (string-match flymake-warning-predicate err-text))
-                        ((functionp flymake-warning-predicate)
-                         (funcall flymake-warning-predicate err-text)))
-              (setq err-type "w")))
-         (flymake-log
-           3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s"
-           file-idx line-idx raw-file-name line-no err-text)
-         (setq matched t)))
-      (setq patterns (cdr patterns)))
-    (if matched
-       (flymake-ler-make-ler raw-file-name line-no err-type err-text)
-      ())))
-
-(defun flymake-find-err-info (err-info-list line-no)
-  "Find (line-err-info-list pos) for specified LINE-NO."
-  (if err-info-list
-      (let* ((line-err-info-list  nil)
-            (pos       0)
-            (count     (length err-info-list)))
-
-       (while (and (< pos count) (< (car (nth pos err-info-list)) line-no))
-         (setq pos (1+ pos)))
-       (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no))
-         (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos 
err-info-list))))
-       (list line-err-info-list pos))
-    '(nil 0)))
-
-(defun flymake-line-err-info-is-less-or-equal (line-one line-two)
-  (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two))
-      (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
-          (not (flymake-ler-file line-one)) (flymake-ler-file line-two))
-      (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two))
-          (or (and      (flymake-ler-file line-one)       (flymake-ler-file 
line-two))
-              (and (not (flymake-ler-file line-one)) (not (flymake-ler-file 
line-two)))))))
-
-(defun flymake-add-line-err-info (line-err-info-list line-err-info)
-  "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO.
-For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'.
-The new element is inserted in the proper position, according to
-the predicate `flymake-line-err-info-is-less-or-equal'.
-The updated value of LINE-ERR-INFO-LIST is returned."
-  (if (not line-err-info-list)
-      (list line-err-info)
-    (let* ((count  (length line-err-info-list))
-          (idx    0))
-      (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth 
idx line-err-info-list) line-err-info))
-       (setq idx (1+ idx)))
-      (cond ((equal 0     idx)    (setq line-err-info-list (cons line-err-info 
line-err-info-list)))
-           (t                    (setq line-err-info-list (flymake-ins-after 
line-err-info-list (1- idx) line-err-info))))
-      line-err-info-list)))
-
-(defun flymake-add-err-info (err-info-list line-err-info)
-  "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order.
-Returns the updated value of ERR-INFO-LIST.
-For the format of ERR-INFO-LIST, see `flymake-err-info'.
-For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'."
-  (let* ((line-no             (if (flymake-ler-file line-err-info) 1 
(flymake-ler-line line-err-info)))
-        (info-and-pos        (flymake-find-err-info err-info-list line-no))
-        (exists              (car info-and-pos))
-        (pos                 (nth 1 info-and-pos))
-        (line-err-info-list  nil)
-        (err-info            nil))
-
-    (if exists
-       (setq line-err-info-list (flymake-er-get-line-err-info-list (car 
(nthcdr pos err-info-list)))))
-    (setq line-err-info-list (flymake-add-line-err-info line-err-info-list 
line-err-info))
-
-    (setq err-info (flymake-er-make-er line-no line-err-info-list))
-    (cond (exists             (setq err-info-list (flymake-set-at 
err-info-list pos err-info)))
-         ((equal 0 pos)      (setq err-info-list (cons err-info 
err-info-list)))
-         (t                  (setq err-info-list (flymake-ins-after 
err-info-list (1- pos) err-info))))
-    err-info-list))
-
-(defun flymake-get-project-include-dirs-imp (basedir)
-  "Include dirs for the project current file belongs to."
-  (if (flymake-get-project-include-dirs-from-cache basedir)
-      (progn
-       (flymake-get-project-include-dirs-from-cache basedir))
-    ;;else
-    (let* ((command-line  (concat "make -C "
-                                 (shell-quote-argument basedir)
-                                 " DUMPVARS=INCLUDE_DIRS dumpvars"))
-          (output        (shell-command-to-string command-line))
-          (lines         (split-string output "\n" t))
-          (count         (length lines))
-          (idx           0)
-          (inc-dirs      nil))
-      (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx 
lines))))
-       (setq idx (1+ idx)))
-      (when (< idx count)
-       (let* ((inc-lines  (split-string (nth idx lines) " *-I" t))
-              (inc-count  (length inc-lines)))
-         (while (> inc-count 0)
-           (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) 
inc-lines)))
-             (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) 
inc-lines)) inc-dirs))
-           (setq inc-count (1- inc-count)))))
-      (flymake-add-project-include-dirs-to-cache basedir inc-dirs)
-      inc-dirs)))
-
-(defvar flymake-get-project-include-dirs-function 
#'flymake-get-project-include-dirs-imp
-  "Function used to get project include dirs, one parameter: basedir name.")
-
-(defun flymake-get-project-include-dirs (basedir)
-  (funcall flymake-get-project-include-dirs-function basedir))
-
-(defun flymake-get-system-include-dirs ()
-  "System include dirs - from the `INCLUDE' env setting."
-  (let* ((includes (getenv "INCLUDE")))
-    (if includes (split-string includes path-separator t) nil)))
-
-(defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal))
-
-(defun flymake-get-project-include-dirs-from-cache (base-dir)
-  (gethash base-dir flymake-project-include-dirs-cache))
-
-(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs)
-  (puthash base-dir include-dirs flymake-project-include-dirs-cache))
-
-(defun flymake-clear-project-include-dirs-cache ()
-  (clrhash flymake-project-include-dirs-cache))
-
-(defun flymake-get-include-dirs (base-dir)
-  "Get dirs to use when resolving local file names."
-  (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs 
base-dir) (flymake-get-system-include-dirs))))
-    include-dirs))
-
-;; (defun flymake-restore-formatting ()
-;;   "Remove any formatting made by flymake."
-;;   )
-
-;; (defun flymake-get-program-dir (buffer)
-;;   "Get dir to start program in."
-;;   (unless (bufferp buffer)
-;;     (error "Invalid buffer"))
-;;   (with-current-buffer buffer
-;;     default-directory))
-
-(defun flymake-safe-delete-file (file-name)
-  (when (and file-name (file-exists-p file-name))
-    (delete-file file-name)
-    (flymake-log 1 "deleted file %s" file-name)))
-
-(defun flymake-safe-delete-directory (dir-name)
-  (condition-case nil
-      (progn
-       (delete-directory dir-name)
-       (flymake-log 1 "deleted dir %s" dir-name))
-    (error
-     (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
-
-(defun flymake-start-syntax-check ()
-  "Start syntax checking for current buffer."
-  (interactive)
-  (flymake-log 3 "flymake is running: %s" flymake-is-running)
-  (when (and (not flymake-is-running)
-             (flymake-can-syntax-check-file buffer-file-name))
-    (when (or (not flymake-compilation-prevents-syntax-check)
-              (not (flymake-compilation-is-running))) ;+ 
(flymake-rep-ort-status buffer "COMP")
-      (flymake-clear-buildfile-cache)
-      (flymake-clear-project-include-dirs-cache)
-
-      (setq flymake-check-was-interrupted nil)
-
-      (let* ((source-file-name  buffer-file-name)
-             (init-f (flymake-get-init-function source-file-name))
-             (cleanup-f (flymake-get-cleanup-function source-file-name))
-             (cmd-and-args (funcall init-f))
-             (cmd          (nth 0 cmd-and-args))
-             (args         (nth 1 cmd-and-args))
-             (dir          (nth 2 cmd-and-args)))
-        (if (not cmd-and-args)
-            (progn
-              (flymake-log 0 "init function %s for %s failed, cleaning up" 
init-f source-file-name)
-              (funcall cleanup-f))
-          (progn
-            (setq flymake-last-change-time nil)
-            (flymake-start-syntax-check-process cmd args dir)))))))
-
-(defun flymake-start-syntax-check-process (cmd args dir)
-  "Start syntax check process."
-  (condition-case err
-      (let* ((process
-              (let ((default-directory (or dir default-directory)))
-                (when dir
-                  (flymake-log 3 "starting process on dir %s" dir))
-                (apply 'start-file-process
-                       "flymake-proc" (current-buffer) cmd args))))
-        (set-process-sentinel process 'flymake-process-sentinel)
-        (set-process-filter process 'flymake-process-filter)
-        (set-process-query-on-exit-flag process nil)
-        (push process flymake-processes)
-
-        (setq flymake-is-running t)
-        (setq flymake-last-change-time nil)
-        (setq flymake-check-start-time (float-time))
+  "Face used for marking warning regions."
+  :version "24.4")
 
-        (flymake-report-status nil "*")
-        (flymake-log 2 "started process %d, command=%s, dir=%s"
-                     (process-id process) (process-command process)
-                     default-directory)
-        process)
-    (error
-     (let* ((err-str
-             (format-message
-              "Failed to launch syntax check process `%s' with args %s: %s"
-              cmd args (error-message-string err)))
-            (source-file-name buffer-file-name)
-            (cleanup-f        (flymake-get-cleanup-function source-file-name)))
-       (flymake-log 0 err-str)
-       (funcall cleanup-f)
-       (flymake-report-fatal-status "PROCERR" err-str)))))
-
-(defun flymake-kill-process (proc)
-  "Kill process PROC."
-  (kill-process proc)
-  (let* ((buf (process-buffer proc)))
-    (when (buffer-live-p buf)
-      (with-current-buffer buf
-       (setq flymake-check-was-interrupted t))))
-  (flymake-log 1 "killed process %d" (process-id proc)))
-
-(defun flymake-stop-all-syntax-checks ()
-  "Kill all syntax check processes."
-  (interactive)
-  (while flymake-processes
-    (flymake-kill-process (pop flymake-processes))))
-
-(defun flymake-compilation-is-running ()
-  (and (boundp 'compilation-in-progress)
-       compilation-in-progress))
-
-(defun flymake-compile ()
-  "Kill all flymake syntax checks, start compilation."
-  (interactive)
-  (flymake-stop-all-syntax-checks)
-  (call-interactively 'compile))
-
-(defun flymake-on-timer-event (buffer)
-  "Start a syntax check for buffer BUFFER if necessary."
-  (when (buffer-live-p buffer)
-    (with-current-buffer buffer
-      (when (and (not flymake-is-running)
-                flymake-last-change-time
-                (> (- (float-time) flymake-last-change-time)
-                    flymake-no-changes-timeout))
-
-       (setq flymake-last-change-time nil)
-       (flymake-log 3 "starting syntax check as more than 1 second passed 
since last change")
-       (flymake-start-syntax-check)))))
-
-(define-obsolete-function-alias 'flymake-display-err-menu-for-current-line
-  'flymake-popup-current-error-menu "24.4")
-
-(defun flymake-popup-current-error-menu (&optional event)
-  "Pop up a menu with errors/warnings for current line."
-  (interactive (list last-nonmenu-event))
-  (let* ((line-no (line-number-at-pos))
-         (errors (or (car (flymake-find-err-info flymake-err-info line-no))
-                     (user-error "No errors for current line")))
-         (menu (mapcar (lambda (x)
-                         (if (flymake-ler-file x)
-                             (cons (format "%s - %s(%d)"
-                                           (flymake-ler-text x)
-                                           (flymake-ler-file x)
-                                           (flymake-ler-line x))
-                                   x)
-                           (list (flymake-ler-text x))))
-                       errors))
-         (event (if (mouse-event-p event)
-                    event
-                  (list 'mouse-1 (posn-at-point))))
-         (title (format "Line %d: %d error(s), %d warning(s)"
-                        line-no
-                        (flymake-get-line-err-count errors "e")
-                        (flymake-get-line-err-count errors "w")))
-         (choice (x-popup-menu event (list title (cons "" menu)))))
-    (flymake-log 3 "choice=%s" choice)
-    (when choice
-      (flymake-goto-file-and-line (flymake-ler-full-file choice)
-                                  (flymake-ler-line choice)))))
-
-(defun flymake-goto-file-and-line (file line)
-  "Try to get buffer for FILE and goto line LINE in it."
-  (if (not (file-exists-p file))
-      (flymake-log 1 "File %s does not exist" file)
-    (find-file file)
-    (goto-char (point-min))
-    (forward-line (1- line))))
-
-;; flymake minor mode declarations
-(defvar-local flymake-mode-line nil)
-(defvar-local flymake-mode-line-e-w nil)
-(defvar-local flymake-mode-line-status nil)
-
-(defun flymake-report-status (e-w &optional status)
-  "Show status in mode line."
-  (when e-w
-    (setq flymake-mode-line-e-w e-w))
-  (when status
-    (setq flymake-mode-line-status status))
-  (let* ((mode-line " Flymake"))
-    (when (> (length flymake-mode-line-e-w) 0)
-      (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
-    (setq mode-line (concat mode-line flymake-mode-line-status))
-    (setq flymake-mode-line mode-line)
-    (force-mode-line-update)))
-
-;; Nothing in flymake uses this at all any more, so this is just for
+(defface flymake-note
+  '((((supports :underline (:style wave)))
+     :underline (:style wave :color "yellow green"))
+    (t
+     :inherit warning))
+  "Face used for marking note regions."
+  :version "26.1")
+
+(define-obsolete-face-alias 'flymake-warnline 'flymake-warning "26.1")
+(define-obsolete-face-alias 'flymake-errline 'flymake-error "26.1")
+
+(defun flymake-diag-region (line &optional col)
+  "Compute region (BEG . END) corresponding to LINE and COL.
+If COL is nil, return a region just for LINE.
+Return nil if the region is invalid."
+  (condition-case-unless-debug _err
+      (let ((line (min (max line 1)
+                       (line-number-at-pos (point-max) 'absolute))))
+        (save-excursion
+          (goto-char (point-min))
+          (forward-line (1- line))
+          (cl-flet ((fallback-bol
+                     () (progn (back-to-indentation) (point)))
+                    (fallback-eol
+                     (beg)
+                     (progn
+                       (end-of-line)
+                       (skip-chars-backward " \t\f\t\n" beg)
+                       (if (eq (point) beg)
+                           (line-beginning-position 2)
+                         (point)))))
+            (if (and col (cl-plusp col))
+                (let* ((beg (progn (forward-char (1- col))
+                                   (point)))
+                       (sexp-end (ignore-errors (end-of-thing 'sexp)))
+                       (end (or (and sexp-end
+                                     (not (= sexp-end beg))
+                                     sexp-end)
+                                (ignore-errors (goto-char (1+ beg)))))
+                       (safe-end (or end
+                                     (fallback-eol beg))))
+                  (cons (if end beg (fallback-bol))
+                        safe-end))
+              (let* ((beg (fallback-bol))
+                     (end (fallback-eol beg)))
+                (cons beg end))))))
+    (error (flymake-error "Invalid region line=%s col=%s" line col))))
+
+(defvar flymake-diagnostic-functions nil
+  "Special hook of Flymake backends that check a buffer.
+
+The functions in this hook diagnose problems in a buffer’s
+contents and provide information to the Flymake user interface
+about where and how to annotate problems diagnosed in a buffer.
+
+Whenever Flymake or the user decides to re-check the buffer, each
+function is called with an arbitrary number of arguments:
+
+* the first argument is always REPORT-FN, a callback function
+  detailed below;
+
+* the remaining arguments are keyword-value pairs in the
+  form (:KEY VALUE :KEY2 VALUE2...).  Currently, Flymake provides
+  no such arguments, but backend functions must be prepared to
+  accept to accept and possibly ignore any number of them.
+
+Backend functions are expected to initiate the buffer check, but
+aren't required to complete it check before exiting: if the
+computation involved is expensive, especially for large buffers,
+that task can be scheduled for the future using asynchronous
+processes or other asynchronous mechanisms.
+
+In any case, backend functions are expected to return quickly or
+signal an error, in which case the backend is disabled.  Flymake
+will not try disabled backends again for any future checks of
+this buffer.  Certain commands, like turning `flymake-mode' off
+and on again, reset the list of disabled backends.
+
+If the function returns, Flymake considers the backend to be
+\"running\". If it has not done so already, the backend is
+expected to call the function REPORT-FN with a single argument
+REPORT-ACTION also followed by an optional list of keyword-value
+pairs in the form (:REPORT-KEY VALUE :REPORT-KEY2 VALUE2...).
+
+Currently accepted values for REPORT-ACTION are:
+
+* A (possibly empty) list of diagnostic objects created with
+  `flymake-make-diagnostic', causing Flymake to annotate the
+  buffer with this information.
+
+  A backend may call REPORT-FN repeatedly in this manner, but
+  only until Flymake considers that the most recently requested
+  buffer check is now obsolete because, say, buffer contents have
+  changed in the meantime. The backend is only given notice of
+  this via a renewed call to the backend function. Thus, to
+  prevent making obsolete reports and wasting resources, backend
+  functions should first cancel any ongoing processing from
+  previous calls.
+
+* The symbol `:panic', signalling that the backend has
+  encountered an exceptional situation and should be disabled.
+
+Currently accepted REPORT-KEY arguments are:
+
+* ‘:explanation’: value should give user-readable details of
+  the situation encountered, if any.
+
+* ‘:force’: value should be a boolean suggesting that the Flymake
+  considers the report even if was somehow unexpected.")
+
+(defvar flymake-diagnostic-types-alist
+  `((:error
+     . ((flymake-category . flymake-error)))
+    (:warning
+     . ((flymake-category . flymake-warning)))
+    (:note
+     . ((flymake-category . flymake-note))))
+  "Alist ((KEY . PROPS)*) of properties of Flymake error types.
+KEY can be anything passed as `:type' to `flymake-diag-make'.
+
+PROPS is an alist of properties that are applied, in order, to
+the diagnostics of each type.  The recognized properties are:
+
+* Every property pertaining to overlays, except `category' and
+  `evaporate' (see Info Node `(elisp)Overlay Properties'), used
+  affect the appearance of Flymake annotations.
+
+* `bitmap', an image displayed in the fringe according to
+  `flymake-fringe-indicator-position'.  The value actually
+  follows the syntax of `flymake-error-bitmap' (which see).  It
+  is overriden by any `before-string' overlay property.
+
+* `severity', a non-negative integer specifying the diagnostic's
+  severity.  The higher, the more serious.  If the overlay
+  priority `priority' is not specified, `severity' is used to set
+  it and help sort overlapping overlays.
+
+* `flymake-category', a symbol whose property list is considered
+  as a default for missing values of any other properties.  This
+  is useful to backend authors when creating new diagnostic types
+  that differ from an existing type by only a few properties.")
+
+(put 'flymake-error 'face 'flymake-error)
+(put 'flymake-error 'bitmap 'flymake-error-bitmap)
+(put 'flymake-error 'severity (warning-numeric-level :error))
+(put 'flymake-error 'mode-line-face 'compilation-error)
+
+(put 'flymake-warning 'face 'flymake-warning)
+(put 'flymake-warning 'bitmap 'flymake-warning-bitmap)
+(put 'flymake-warning 'severity (warning-numeric-level :warning))
+(put 'flymake-warning 'mode-line-face 'compilation-warning)
+
+(put 'flymake-note 'face 'flymake-note)
+(put 'flymake-note 'bitmap 'flymake-note-bitmap)
+(put 'flymake-note 'severity (warning-numeric-level :debug))
+(put 'flymake-note 'mode-line-face 'compilation-info)
+
+(defun flymake--lookup-type-property (type prop &optional default)
+  "Look up PROP for TYPE in `flymake-diagnostic-types-alist'.
+If TYPE doesn't declare PROP in either
+`flymake-diagnostic-types-alist' or in the symbol of its
+associated `flymake-category' return DEFAULT."
+  (let ((alist-probe (assoc type flymake-diagnostic-types-alist)))
+    (cond (alist-probe
+           (let* ((alist (cdr alist-probe))
+                  (prop-probe (assoc prop alist)))
+             (if prop-probe
+                 (cdr prop-probe)
+               (if-let* ((cat (assoc-default 'flymake-category alist))
+                         (plist (and (symbolp cat)
+                                     (symbol-plist cat)))
+                         (cat-probe (plist-member plist prop)))
+                   (cadr cat-probe)
+                 default))))
+          (t
+           default))))
+
+(defun flymake--fringe-overlay-spec (bitmap &optional recursed)
+  (if (and (symbolp bitmap)
+           (boundp bitmap)
+           (not recursed))
+      (flymake--fringe-overlay-spec
+       (symbol-value bitmap) t)
+    (and flymake-fringe-indicator-position
+         bitmap
+         (propertize "!" 'display
+                     (cons flymake-fringe-indicator-position
+                           (if (listp bitmap)
+                               bitmap
+                             (list bitmap)))))))
+
+(defun flymake--highlight-line (diagnostic)
+  "Highlight buffer with info in DIAGNOSTIC."
+  (when-let* ((ov (make-overlay
+                   (flymake--diag-beg diagnostic)
+                   (flymake--diag-end diagnostic))))
+    ;; First set `category' in the overlay, then copy over every other
+    ;; property.
+    ;;
+    (let ((alist (assoc-default (flymake--diag-type diagnostic)
+                                flymake-diagnostic-types-alist)))
+      (overlay-put ov 'category (assoc-default 'flymake-category alist))
+      (cl-loop for (k . v) in alist
+               unless (eq k 'category)
+               do (overlay-put ov k v)))
+    ;; Now ensure some essential defaults are set
+    ;;
+    (cl-flet ((default-maybe
+                (prop value)
+                (unless (or (plist-member (overlay-properties ov) prop)
+                            (let ((cat (overlay-get ov
+                                                    'flymake-category)))
+                              (and cat
+                                   (plist-member (symbol-plist cat) prop))))
+                  (overlay-put ov prop value))))
+      (default-maybe 'bitmap 'flymake-error-bitmap)
+      (default-maybe 'face 'flymake-error)
+      (default-maybe 'before-string
+        (flymake--fringe-overlay-spec
+         (overlay-get ov 'bitmap)))
+      (default-maybe 'help-echo
+        (lambda (_window _ov pos)
+          (mapconcat
+           (lambda (ov)
+             (let ((diag (overlay-get ov 'flymake--diagnostic)))
+               (flymake--diag-text diag)))
+           (flymake--overlays :beg pos)
+           "\n")))
+      (default-maybe 'severity (warning-numeric-level :error))
+      (default-maybe 'priority (+ 100 (overlay-get ov 'severity))))
+    ;; Some properties can't be overriden
+    ;;
+    (overlay-put ov 'evaporate t)
+    (overlay-put ov 'flymake t)
+    (overlay-put ov 'flymake--diagnostic diagnostic)))
+
+;; Nothing in Flymake uses this at all any more, so this is just for
 ;; third-party compatibility.
 (define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1")
 
-(defun flymake-report-fatal-status (status warning)
-  "Display a warning and switch flymake mode off."
-  ;; This first message was always shown by default, and flymake-log
-  ;; does nothing by default, hence the use of message.
-  ;; Another option is display-warning.
-  (if (< flymake-log-level 0)
-      (message "Flymake: %s. Flymake will be switched OFF" warning))
-  (flymake-mode 0)
-  (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status 
%s, warning %s"
-               (buffer-name) status warning))
+(defvar-local flymake--backend-state nil
+  "Buffer-local hash table of a Flymake backend's state.
+The keys to this hash table are functions as found in
+`flymake-diagnostic-functions'. The values are structures
+of the type `flymake--backend-state', with these slots
+
+`running', a symbol to keep track of a backend's replies via its
+REPORT-FN argument. A backend is running if this key is
+present. If the key is absent if the backend isn't expecting any
+replies from the backend.
+
+`diags', a (possibly empty) list of diagnostic objects created
+with `flymake-make-diagnostic'. This key is absent if the
+backend hasn't reported anything yet.
+
+`reported-p', a boolean indicating if the backend has replied
+since it last was contacted.
+
+`disabled', a string with the explanation for a previous
+exceptional situation reported by the backend. If this key is
+present the backend is disabled.")
+
+(cl-defstruct (flymake--backend-state
+               (:constructor flymake--make-backend-state))
+  running reported-p disabled diags)
+
+(defmacro flymake--with-backend-state (backend state-var &rest body)
+  "Bind BACKEND's STATE-VAR to its state, run BODY."
+  (declare (indent 2) (debug (sexp sexp &rest form)))
+  (let ((b (make-symbol "b")))
+    `(let* ((,b ,backend)
+            (,state-var
+             (or (gethash ,b flymake--backend-state)
+                 (puthash ,b (flymake--make-backend-state)
+                          flymake--backend-state))))
+       ,@body)))
+
+(defun flymake-is-running ()
+  "Tell if Flymake has running backends in this buffer"
+  (flymake-running-backends))
+
+(cl-defun flymake--handle-report (backend token report-action
+                                          &key explanation force
+                                          &allow-other-keys)
+  "Handle reports from BACKEND identified by TOKEN.
+
+BACKEND, REPORT-ACTION and EXPLANATION, and FORCE conform to the calling
+convention described in `flymake-diagnostic-functions' (which
+see). Optional FORCE says to handle a report even if TOKEN was
+not expected."
+  (let* ((state (gethash backend flymake--backend-state))
+         (first-report (not (flymake--backend-state-reported-p state))))
+    (setf (flymake--backend-state-reported-p state) t)
+    (let (expected-token
+          new-diags)
+      (cond
+       ((null state)
+        (flymake-error
+         "Unexpected report from unknown backend %s" backend))
+       ((flymake--backend-state-disabled state)
+        (flymake-error
+         "Unexpected report from disabled backend %s" backend))
+       ((progn
+          (setq expected-token (flymake--backend-state-running state))
+          (null expected-token))
+        ;; should never happen
+        (flymake-error "Unexpected report from stopped backend %s" backend))
+       ((and (not (eq expected-token token))
+             (not force))
+        (flymake-error "Obsolete report from backend %s with explanation %s"
+                       backend explanation))
+       ((eq :panic report-action)
+        (flymake--disable-backend backend explanation))
+       ((not (listp report-action))
+        (flymake--disable-backend backend
+                                  (format "Unknown action %S" report-action))
+        (flymake-error "Expected report, but got unknown key %s" 
report-action))
+       (t
+        (setq new-diags report-action)
+        (save-restriction
+          (widen)
+          ;; only delete overlays if this is the first report
+          (when first-report
+            (flymake-delete-own-overlays
+             (lambda (ov)
+               (eq backend
+                   (flymake--diag-backend
+                    (overlay-get ov 'flymake--diagnostic))))))
+          (mapc (lambda (diag)
+                  (flymake--highlight-line diag)
+                  (setf (flymake--diag-backend diag) backend))
+                new-diags)
+          (setf (flymake--backend-state-diags state)
+                (append new-diags (flymake--backend-state-diags state)))
+          (when flymake-check-start-time
+            (flymake-log :debug "backend %s reported %d diagnostics in %.2f 
second(s)"
+                         backend
+                         (length new-diags)
+                         (- (float-time) flymake-check-start-time)))))))))
+
+(defun flymake-make-report-fn (backend &optional token)
+  "Make a suitable anonymous report function for BACKEND.
+BACKEND is used to help Flymake distinguish different diagnostic
+sources.  If provided, TOKEN helps Flymake distinguish between
+different runs of the same backend."
+  (let ((buffer (current-buffer)))
+    (lambda (&rest args)
+      (when (buffer-live-p buffer)
+        (with-current-buffer buffer
+          (apply #'flymake--handle-report backend token args))))))
+
+(defun flymake--collect (fn)
+  (let (retval)
+    (maphash (lambda (backend state)
+               (when (funcall fn state) (push backend retval)))
+             flymake--backend-state)
+    retval))
+
+(defun flymake-running-backends ()
+  "Compute running Flymake backends in current buffer."
+  (flymake--collect #'flymake--backend-state-running))
+
+(defun flymake-disabled-backends ()
+  "Compute disabled Flymake backends in current buffer."
+  (flymake--collect #'flymake--backend-state-disabled))
+
+(defun flymake-reporting-backends ()
+  "Compute reporting Flymake backends in current buffer."
+  (flymake--collect #'flymake--backend-state-reported-p))
+
+(defun flymake--disable-backend (backend &optional explanation)
+  "Disable BACKEND because EXPLANATION.
+If is is running also stop it."
+  (flymake-log :warning "Disabling backend %s because %s" backend explanation)
+  (flymake--with-backend-state backend state
+    (setf (flymake--backend-state-running state) nil
+          (flymake--backend-state-disabled state) explanation
+          (flymake--backend-state-reported-p state) t)))
+
+(defun flymake--run-backend (backend)
+  "Run the backend BACKEND, reenabling if necessary."
+  (flymake-log :debug "Running backend %s" backend)
+  (let ((run-token (cl-gensym "backend-token")))
+    (flymake--with-backend-state backend state
+      (setf (flymake--backend-state-running state) run-token
+            (flymake--backend-state-disabled state) nil
+            (flymake--backend-state-diags state) nil
+            (flymake--backend-state-reported-p state) nil))
+    ;; FIXME: Should use `condition-case-unless-debug' here, for don't
+    ;; for two reasons: (1) that won't let me catch errors from inside
+    ;; `ert-deftest' where `debug-on-error' appears to be always
+    ;; t. (2) In cases where the user is debugging elisp somewhere
+    ;; else, and using flymake, the presence of a frequently
+    ;; misbehaving backend in the global hook (most likely the legacy
+    ;; backend) will trigger an annoying backtrace.
+    ;;
+    (condition-case err
+        (funcall backend
+                 (flymake-make-report-fn backend run-token))
+      (error
+       (flymake--disable-backend backend err)))))
+
+(defun flymake-start (&optional deferred force)
+  "Start a syntax check.
+Start it immediately, or after current command if DEFERRED is
+non-nil.  With optional FORCE run even disabled backends.
+
+Interactively, with a prefix arg, FORCE is t."
+  (interactive (list nil current-prefix-arg))
+  (cl-labels
+      ((start
+        ()
+        (remove-hook 'post-command-hook #'start 'local)
+        (setq flymake-check-start-time (float-time))
+        (run-hook-wrapped
+         'flymake-diagnostic-functions
+         (lambda (backend)
+           (cond
+            ((and (not force)
+                  (flymake--with-backend-state backend state
+                    (flymake--backend-state-disabled state)))
+             (flymake-log :debug "Backend %s is disabled, not starting"
+                          backend))
+            (t
+             (flymake--run-backend backend)))
+           nil))))
+    (if (and deferred
+             this-command)
+        (add-hook 'post-command-hook #'start 'append 'local)
+      (start))))
+
+(defvar flymake-mode-map
+  (let ((map (make-sparse-keymap))) map)
+  "Keymap for `flymake-mode'")
 
 ;;;###autoload
 (define-minor-mode flymake-mode nil
-  :group 'flymake :lighter flymake-mode-line
+  :group 'flymake :lighter flymake--mode-line-format :keymap flymake-mode-map
   (cond
-
    ;; Turning the mode ON.
    (flymake-mode
     (cond
-     ((not buffer-file-name)
-      (message "Flymake unable to run without a buffer file name"))
-     ((not (flymake-can-syntax-check-file buffer-file-name))
-      (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
+     ((not flymake-diagnostic-functions)
+      (flymake-error "No backends to check buffer %s" (buffer-name)))
      (t
       (add-hook 'after-change-functions 'flymake-after-change-function nil t)
       (add-hook 'after-save-hook 'flymake-after-save-hook nil t)
       (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)
-      ;;+(add-hook 'find-file-hook 'flymake-find-file-hook)
 
-      (flymake-report-status "" "")
+      (setq flymake--backend-state (make-hash-table))
 
-      (setq flymake-timer
-            (run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
-
-      (when (and flymake-start-syntax-check-on-find-file
-                 ;; Since we write temp files in current dir, there's no point
-                 ;; trying if the directory is read-only (bug#8954).
-                 (file-writable-p (file-name-directory buffer-file-name)))
-        (with-demoted-errors
-            (flymake-start-syntax-check))))))
+      (when flymake-start-syntax-check-on-find-file
+        (flymake-start)))))
 
    ;; Turning the mode OFF.
    (t
@@ -1251,402 +736,248 @@ For the format of LINE-ERR-INFO, see 
`flymake-ler-make-ler'."
 
     (when flymake-timer
       (cancel-timer flymake-timer)
-      (setq flymake-timer nil))
-
-    (setq flymake-is-running nil))))
+      (setq flymake-timer nil)))))
+
+(defun flymake--schedule-timer-maybe ()
+  "(Re)schedule an idle timer for checking the buffer.
+Do it only if `flymake-no-changes-timeout' is non-nil."
+  (when flymake-timer (cancel-timer flymake-timer))
+  (when flymake-no-changes-timeout
+    (setq
+     flymake-timer
+     (run-with-idle-timer
+      (seconds-to-time flymake-no-changes-timeout)
+      nil
+      (lambda (buffer)
+        (when (buffer-live-p buffer)
+          (with-current-buffer buffer
+            (when (and flymake-mode
+                       flymake-no-changes-timeout)
+             (flymake-log
+               :debug "starting syntax check after idle for %s seconds"
+               flymake-no-changes-timeout)
+             (flymake-start))
+            (setq flymake-timer nil))))
+      (current-buffer)))))
 
 ;;;###autoload
 (defun flymake-mode-on ()
-  "Turn flymake mode on."
-  (flymake-mode 1)
-  (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name)))
+  "Turn Flymake mode on."
+  (flymake-mode 1))
 
 ;;;###autoload
 (defun flymake-mode-off ()
-  "Turn flymake mode off."
-  (flymake-mode 0)
-  (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name)))
+  "Turn Flymake mode off."
+  (flymake-mode 0))
+
+(make-obsolete 'flymake-mode-on 'flymake-mode "26.1")
+(make-obsolete 'flymake-mode-off 'flymake-mode "26.1")
 
 (defun flymake-after-change-function (start stop _len)
   "Start syntax check for current buffer if it isn't already running."
-  ;;+(flymake-log 0 "setting change time to %s" (float-time))
   (let((new-text (buffer-substring start stop)))
     (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
-      (flymake-log 3 "starting syntax check as new-line has been seen")
-      (flymake-start-syntax-check))
-    (setq flymake-last-change-time (float-time))))
+      (flymake-log :debug "starting syntax check as new-line has been seen")
+      (flymake-start 'deferred))
+    (flymake--schedule-timer-maybe)))
 
 (defun flymake-after-save-hook ()
-  (if (local-variable-p 'flymake-mode (current-buffer))        ; (???) other 
way to determine whether flymake is active in buffer being saved?
-      (progn
-       (flymake-log 3 "starting syntax check as buffer was saved")
-       (flymake-start-syntax-check)))) ; no more mode 3. cannot start check if 
mode 3 (to temp copies) is active - (???)
+  (when flymake-mode
+    (flymake-log :debug "starting syntax check as buffer was saved")
+    (flymake-start)))
 
 (defun flymake-kill-buffer-hook ()
   (when flymake-timer
     (cancel-timer flymake-timer)
     (setq flymake-timer nil)))
 
-;;;###autoload
 (defun flymake-find-file-hook ()
-  ;;+(when flymake-start-syntax-check-on-find-file
-  ;;+    (flymake-log 3 "starting syntax check on file open")
-  ;;+    (flymake-start-syntax-check)
-  ;;+)
-  (when (and (not (local-variable-p 'flymake-mode (current-buffer)))
-            (flymake-can-syntax-check-file buffer-file-name))
+  (unless (or flymake-mode
+              (null flymake-diagnostic-functions))
     (flymake-mode)
-    (flymake-log 3 "automatically turned ON flymake mode")))
-
-(defun flymake-get-first-err-line-no (err-info-list)
-  "Return first line with error."
-  (when err-info-list
-    (flymake-er-get-line (car err-info-list))))
-
-(defun flymake-get-last-err-line-no (err-info-list)
-  "Return last line with error."
-  (when err-info-list
-    (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list))))
-
-(defun flymake-get-next-err-line-no (err-info-list line-no)
-  "Return next line with error."
-  (when err-info-list
-    (let* ((count  (length err-info-list))
-          (idx    0))
-      (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx 
err-info-list))))
-       (setq idx (1+ idx)))
-      (if (< idx count)
-         (flymake-er-get-line (nth idx err-info-list))))))
-
-(defun flymake-get-prev-err-line-no (err-info-list line-no)
-  "Return previous line with error."
-  (when err-info-list
-    (let* ((count (length err-info-list)))
-      (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) 
err-info-list))))
-       (setq count (1- count)))
-      (if (> count 0)
-         (flymake-er-get-line (nth (1- count) err-info-list))))))
-
-(defun flymake-skip-whitespace ()
-  "Move forward until non-whitespace is reached."
-  (while (looking-at "[ \t]")
-    (forward-char)))
-
-(defun flymake-goto-line (line-no)
-  "Go to line LINE-NO, then skip whitespace."
-  (goto-char (point-min))
-  (forward-line (1- line-no))
-  (flymake-skip-whitespace))
-
-(defun flymake-goto-next-error ()
-  "Go to next error in err ring."
-  (interactive)
-  (let ((line-no (flymake-get-next-err-line-no flymake-err-info 
(line-number-at-pos))))
-    (when (not line-no)
-      (setq line-no (flymake-get-first-err-line-no flymake-err-info))
-      (flymake-log 1 "passed end of file"))
-    (if line-no
-       (flymake-goto-line line-no)
-      (flymake-log 1 "no errors in current buffer"))))
-
-(defun flymake-goto-prev-error ()
-  "Go to previous error in err ring."
-  (interactive)
-  (let ((line-no (flymake-get-prev-err-line-no flymake-err-info 
(line-number-at-pos))))
-    (when (not line-no)
-      (setq line-no (flymake-get-last-err-line-no flymake-err-info))
-      (flymake-log 1 "passed beginning of file"))
-    (if line-no
-       (flymake-goto-line line-no)
-      (flymake-log 1 "no errors in current buffer"))))
-
-(defun flymake-patch-err-text (string)
-  (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string)
-      (match-string 1 string)
-    string))
-
-;;;; general init-cleanup and helper routines
-(defun flymake-create-temp-inplace (file-name prefix)
-  (unless (stringp file-name)
-    (error "Invalid file-name"))
-  (or prefix
-      (setq prefix "flymake"))
-  (let* ((ext (file-name-extension file-name))
-        (temp-name (file-truename
-                    (concat (file-name-sans-extension file-name)
-                            "_" prefix
-                            (and ext (concat "." ext))))))
-    (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
-    temp-name))
-
-(defun flymake-create-temp-with-folder-structure (file-name _prefix)
-  (unless (stringp file-name)
-    (error "Invalid file-name"))
-
-  (let* ((dir       (file-name-directory file-name))
-         ;; Not sure what this slash-pos is all about, but I guess it's just
-         ;; trying to remove the leading / of absolute file names.
-        (slash-pos (string-match "/" dir))
-        (temp-dir  (expand-file-name (substring dir (1+ slash-pos))
-                                      temporary-file-directory)))
-
-    (file-truename (expand-file-name (file-name-nondirectory file-name)
-                                     temp-dir))))
-
-(defun flymake-delete-temp-directory (dir-name)
-  "Attempt to delete temp dir created by 
`flymake-create-temp-with-folder-structure', do not fail on error."
-  (let* ((temp-dir    temporary-file-directory)
-        (suffix      (substring dir-name (1+ (length temp-dir)))))
-
-    (while (> (length suffix) 0)
-      (setq suffix (directory-file-name suffix))
-      ;;+(flymake-log 0 "suffix=%s" suffix)
-      (flymake-safe-delete-directory
-       (file-truename (expand-file-name suffix temp-dir)))
-      (setq suffix (file-name-directory suffix)))))
-
-(defvar-local flymake-temp-source-file-name nil)
-(defvar-local flymake-master-file-name nil)
-(defvar-local flymake-temp-master-file-name nil)
-(defvar-local flymake-base-dir nil)
-
-(defun flymake-init-create-temp-buffer-copy (create-temp-f)
-  "Make a temporary copy of the current buffer, save its name in buffer data 
and return the name."
-  (let*  ((source-file-name       buffer-file-name)
-         (temp-source-file-name  (funcall create-temp-f source-file-name 
"flymake")))
-
-    (flymake-save-buffer-in-file temp-source-file-name)
-    (setq flymake-temp-source-file-name temp-source-file-name)
-    temp-source-file-name))
-
-(defun flymake-simple-cleanup ()
-  "Do cleanup after `flymake-init-create-temp-buffer-copy'.
-Delete temp file."
-  (flymake-safe-delete-file flymake-temp-source-file-name)
-  (setq flymake-last-change-time nil))
-
-(defun flymake-get-real-file-name (file-name-from-err-msg)
-  "Translate file name from error message to \"real\" file name.
-Return full-name.  Names are real, not patched."
-  (let* ((real-name            nil)
-        (source-file-name      buffer-file-name)
-        (master-file-name      flymake-master-file-name)
-        (temp-source-file-name flymake-temp-source-file-name)
-        (temp-master-file-name flymake-temp-master-file-name)
-        (base-dirs
-          (list flymake-base-dir
-                (file-name-directory source-file-name)
-                (if master-file-name (file-name-directory master-file-name))))
-        (files (list (list source-file-name       source-file-name)
-                      (list temp-source-file-name  source-file-name)
-                      (list master-file-name       master-file-name)
-                      (list temp-master-file-name  master-file-name))))
-
-    (when (equal 0 (length file-name-from-err-msg))
-      (setq file-name-from-err-msg source-file-name))
-
-    (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg 
base-dirs files))
-    ;; if real-name is nil, than file name from err msg is none of the files 
we've patched
-    (if (not real-name)
-       (setq real-name (flymake-get-full-nonpatched-file-name 
file-name-from-err-msg base-dirs)))
-    (if (not real-name)
-       (setq real-name file-name-from-err-msg))
-    (setq real-name (flymake-fix-file-name real-name))
-    (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" 
file-name-from-err-msg real-name)
-    real-name))
-
-(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs 
files)
-  (let* ((base-dirs-count  (length base-dirs))
-        (file-count       (length files))
-        (real-name        nil))
-
-    (while (and (not real-name) (> base-dirs-count 0))
-      (setq file-count (length files))
-      (while (and (not real-name) (> file-count 0))
-       (let* ((this-dir        (nth (1- base-dirs-count) base-dirs))
-              (this-file       (nth 0 (nth (1- file-count) files)))
-              (this-real-name  (nth 1 (nth (1- file-count) files))))
-         ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" 
this-dir this-file this-real-name file-name-from-err-msg)
-         (when (and this-dir this-file (flymake-same-files
-                                        (expand-file-name 
file-name-from-err-msg this-dir)
-                                        this-file))
-           (setq real-name this-real-name)))
-       (setq file-count (1- file-count)))
-      (setq base-dirs-count (1- base-dirs-count)))
-    real-name))
-
-(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
-  (let* ((real-name  nil))
-    (if (file-name-absolute-p file-name-from-err-msg)
-       (setq real-name file-name-from-err-msg)
-      (let* ((base-dirs-count  (length base-dirs)))
-       (while (and (not real-name) (> base-dirs-count 0))
-         (let* ((full-name (expand-file-name file-name-from-err-msg
-                                             (nth (1- base-dirs-count) 
base-dirs))))
-           (if (file-exists-p full-name)
-               (setq real-name full-name))
-           (setq base-dirs-count (1- base-dirs-count))))))
-    real-name))
-
-(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name)
-  "Find buildfile, store its dir in buffer data and return its dir, if found."
-  (let* ((buildfile-dir
-          (flymake-find-buildfile buildfile-name
-                                  (file-name-directory source-file-name))))
-    (if buildfile-dir
-        (setq flymake-base-dir buildfile-dir)
-      (flymake-log 1 "no buildfile (%s) for %s" buildfile-name 
source-file-name)
-      (flymake-report-fatal-status
-       "NOMK" (format "No buildfile (%s) found for %s"
-                      buildfile-name source-file-name)))))
-
-(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f 
create-temp-f master-file-masks include-regexp)
-  "Find master file (or buffer), create its copy along with a copy of the 
source file."
-  (let* ((source-file-name       buffer-file-name)
-        (temp-source-file-name  (flymake-init-create-temp-buffer-copy 
create-temp-f))
-        (master-and-temp-master (flymake-create-master-file
-                                 source-file-name temp-source-file-name
-                                 get-incl-dirs-f create-temp-f
-                                 master-file-masks include-regexp)))
-
-    (if (not master-and-temp-master)
-       (progn
-         (flymake-log 1 "cannot find master file for %s" source-file-name)
-          (flymake-report-status "!" "")       ; NOMASTER
-          nil)
-      (setq flymake-master-file-name (nth 0 master-and-temp-master))
-      (setq flymake-temp-master-file-name (nth 1 master-and-temp-master)))))
-
-(defun flymake-master-cleanup ()
-  (flymake-simple-cleanup)
-  (flymake-safe-delete-file flymake-temp-master-file-name))
-
-;;;; make-specific init-cleanup routines
-(defun flymake-get-syntax-check-program-args (source-file-name base-dir 
use-relative-base-dir use-relative-source get-cmd-line-f)
-  "Create a command line for syntax check using GET-CMD-LINE-F."
-  (funcall get-cmd-line-f
-           (if use-relative-source
-               (file-relative-name source-file-name base-dir)
-             source-file-name)
-           (if use-relative-base-dir
-               (file-relative-name base-dir
-                                   (file-name-directory source-file-name))
-             base-dir)))
-
-(defun flymake-get-make-cmdline (source base-dir)
-  (list "make"
-       (list "-s"
-             "-C"
-             base-dir
-             (concat "CHK_SOURCES=" source)
-             "SYNTAX_CHECK_MODE=1"
-             "check-syntax")))
-
-(defun flymake-get-ant-cmdline (source base-dir)
-  (list "ant"
-       (list "-buildfile"
-             (concat base-dir "/" "build.xml")
-             (concat "-DCHK_SOURCES=" source)
-             "check-syntax")))
-
-(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir 
use-relative-source build-file-name get-cmdline-f)
-  "Create syntax check command line for a directly checked source file.
-Use CREATE-TEMP-F for creating temp copy."
-  (let* ((args nil)
-        (source-file-name   buffer-file-name)
-        (buildfile-dir      (flymake-init-find-buildfile-dir source-file-name 
build-file-name)))
-    (if buildfile-dir
-       (let* ((temp-source-file-name  (flymake-init-create-temp-buffer-copy 
create-temp-f)))
-         (setq args (flymake-get-syntax-check-program-args 
temp-source-file-name buildfile-dir
-                                                           
use-relative-base-dir use-relative-source
-                                                           get-cmdline-f))))
-    args))
-
-(defun flymake-simple-make-init ()
-  (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 
'flymake-get-make-cmdline))
-
-(defun flymake-master-make-init (get-incl-dirs-f master-file-masks 
include-regexp)
-  "Create make command line for a source file checked via master file 
compilation."
-  (let* ((make-args nil)
-        (temp-master-file-name 
(flymake-init-create-temp-source-and-master-buffer-copy
-                                 get-incl-dirs-f 'flymake-create-temp-inplace
-                                master-file-masks include-regexp)))
-    (when temp-master-file-name
-      (let* ((buildfile-dir (flymake-init-find-buildfile-dir 
temp-master-file-name "Makefile")))
-       (if  buildfile-dir
-           (setq make-args (flymake-get-syntax-check-program-args
-                            temp-master-file-name buildfile-dir nil nil 
'flymake-get-make-cmdline)))))
-    make-args))
-
-(defun flymake-find-make-buildfile (source-dir)
-  (flymake-find-buildfile "Makefile" source-dir))
-
-;;;; .h/make specific
-(defun flymake-master-make-header-init ()
-  (flymake-master-make-init
-   'flymake-get-include-dirs
-   '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'")
-   "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\""))
-
-;;;; .java/make specific
-(defun flymake-simple-make-java-init ()
-  (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure 
nil nil "Makefile" 'flymake-get-make-cmdline))
-
-(defun flymake-simple-ant-java-init ()
-  (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure 
nil nil "build.xml" 'flymake-get-ant-cmdline))
-
-(defun flymake-simple-java-cleanup ()
-  "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs."
-  (flymake-safe-delete-file flymake-temp-source-file-name)
-  (when flymake-temp-source-file-name
-    (flymake-delete-temp-directory
-     (file-name-directory flymake-temp-source-file-name))))
-
-;;;; perl-specific init-cleanup routines
-(defun flymake-perl-init ()
-  (let* ((temp-file   (flymake-init-create-temp-buffer-copy
-                       'flymake-create-temp-inplace))
-        (local-file  (file-relative-name
-                       temp-file
-                       (file-name-directory buffer-file-name))))
-    (list "perl" (list "-wc " local-file))))
-
-;;;; php-specific init-cleanup routines
-(defun flymake-php-init ()
-  (let* ((temp-file   (flymake-init-create-temp-buffer-copy
-                       'flymake-create-temp-inplace))
-        (local-file  (file-relative-name
-                       temp-file
-                       (file-name-directory buffer-file-name))))
-    (list "php" (list "-f" local-file "-l"))))
-
-;;;; tex-specific init-cleanup routines
-(defun flymake-get-tex-args (file-name)
-  ;;(list "latex" (list "-c-style-errors" file-name))
-  (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
-
-(defun flymake-simple-tex-init ()
-  (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 
'flymake-create-temp-inplace)))
-
-;; Perhaps there should be a buffer-local variable flymake-master-file
-;; that people can set to override this stuff.  Could inherit from
-;; the similar AUCTeX variable.
-(defun flymake-master-tex-init ()
-  (let* ((temp-master-file-name 
(flymake-init-create-temp-source-and-master-buffer-copy
-                                 'flymake-get-include-dirs-dot 
'flymake-create-temp-inplace
-                                '("\\.tex\\'")
-                                "[ \t]*\\in\\(?:put\\|clude\\)[ 
\t]*{\\(.*%s\\)}")))
-    (when temp-master-file-name
-      (flymake-get-tex-args temp-master-file-name))))
-
-(defun flymake-get-include-dirs-dot (_base-dir)
-  '("."))
-
-;;;; xml-specific init-cleanup routines
-(defun flymake-xml-init ()
-  (list flymake-xml-program
-        (list "val" (flymake-init-create-temp-buffer-copy
-                     'flymake-create-temp-inplace))))
+    (flymake-log :warning "Turned on in `flymake-find-file-hook'")))
+
+(defun flymake-goto-next-error (&optional n filter interactive)
+  "Go to Nth next Flymake error in buffer matching FILTER.
+
+Interactively, always move to the next error.  Interactively, and
+with a prefix arg, skip any diagnostics with a severity less than
+‘:warning’.
+
+If ‘flymake-wrap-around’ is non-nil, resumes search from top
+at end of buffer.
+
+FILTER is a list of diagnostic types found in
+`flymake-diagnostic-types-alist', or nil, if no filter is to be
+applied."
+  ;; TODO: let filter be a number, a severity below which diags are
+  ;; skipped.
+  (interactive (list 1
+                     (if current-prefix-arg
+                         '(:error :warning))
+                     t))
+  (let* ((n (or n 1))
+         (ovs (flymake--overlays :filter
+                                 (lambda (ov)
+                                   (let ((diag (overlay-get
+                                                ov
+                                                'flymake--diagnostic)))
+                                     (and diag
+                                          (or (not filter)
+                                              (memq (flymake--diag-type diag)
+                                                    filter)))))
+                                 :compare (if (cl-plusp n) #'< #'>)
+                                 :key #'overlay-start))
+         (tail (cl-member-if (lambda (ov)
+                               (if (cl-plusp n)
+                                   (> (overlay-start ov)
+                                      (point))
+                                 (< (overlay-start ov)
+                                    (point))))
+                             ovs))
+         (chain (if flymake-wrap-around
+                    (if tail
+                        (progn (setcdr (last tail) ovs) tail)
+                      (and ovs (setcdr (last ovs) ovs)))
+                  tail))
+         (target (nth (1- n) chain)))
+    (cond (target
+           (goto-char (overlay-start target))
+           (when interactive
+             (message
+              (funcall (overlay-get target 'help-echo)
+                       nil nil (point)))))
+          (interactive
+           (user-error "No more Flymake errors%s"
+                       (if filter
+                           (format " of types %s" filter)
+                         ""))))))
+
+(defun flymake-goto-prev-error (&optional n filter interactive)
+  "Go to Nth previous Flymake error in buffer matching FILTER.
+
+Interactively, always move to the previous error.  Interactively,
+and with a prefix arg, skip any diagnostics with a severity less
+than ‘:warning’.
+
+If ‘flymake-wrap-around’ is non-nil, resumes search from top
+at end of buffer.
+
+FILTER is a list of diagnostic types found in
+`flymake-diagnostic-types-alist', or nil, if no filter is to be
+applied."
+  (interactive (list 1 (if current-prefix-arg
+                           '(:error :warning))
+                     t))
+  (flymake-goto-next-error (- (or n 1)) filter interactive))
+
+
+;;; Mode-line fanciness
+;;;
+(defvar flymake--mode-line-format `(:eval (flymake--mode-line-format)))
+
+(put 'flymake--mode-line-format 'risky-local-variable t)
+
+(defun flymake--mode-line-format ()
+  "Produce a pretty minor mode indicator."
+  (let* ((known (hash-table-keys flymake--backend-state))
+         (running (flymake-running-backends))
+         (disabled (flymake-disabled-backends))
+         (reported (flymake-reporting-backends))
+         (diags-by-type (make-hash-table))
+         (all-disabled (and disabled (null running)))
+         (some-waiting (cl-set-difference running reported)))
+    (maphash (lambda (_b state)
+               (mapc (lambda (diag)
+                       (push diag
+                             (gethash (flymake--diag-type diag)
+                                      diags-by-type)))
+                     (flymake--backend-state-diags state)))
+             flymake--backend-state)
+    `((:propertize " Flymake"
+                   mouse-face mode-line-highlight
+                   help-echo
+                   ,(concat (format "%s known backends\n" (length known))
+                            (format "%s running\n" (length running))
+                            (format "%s disabled\n" (length disabled))
+                            "mouse-1: go to log buffer ")
+                   keymap
+                   ,(let ((map (make-sparse-keymap)))
+                      (define-key map [mode-line mouse-1]
+                        (lambda (_event)
+                          (interactive "e")
+                          (switch-to-buffer "*Flymake log*")))
+                      map))
+      ,@(pcase-let ((`(,ind ,face ,explain)
+                     (cond ((null known)
+                            `("?" mode-line "No known backends"))
+                           (some-waiting
+                            `("Wait" compilation-mode-line-run
+                              ,(format "Waiting for %s running backends"
+                                       (length running))))
+                           (all-disabled
+                            `("!" compilation-mode-line-run
+                              "All backends disabled"))
+                           (t
+                            `(nil nil nil)))))
+          (when ind
+            `((":"
+               (:propertize ,ind
+                            face ,face
+                            help-echo ,explain)))))
+      ,@(unless (or all-disabled
+                    (null known))
+          (cl-loop
+           for (type . severity)
+           in (cl-sort (mapcar (lambda (type)
+                                 (cons type (flymake--lookup-type-property
+                                             type
+                                             'severity
+                                             (warning-numeric-level :error))))
+                               (cl-union (hash-table-keys diags-by-type)
+                                         '(:error :warning)))
+                       #'>
+                       :key #'cdr)
+           for diags = (gethash type diags-by-type)
+           for face = (flymake--lookup-type-property type
+                                                     'mode-line-face
+                                                     'compilation-error)
+           when (or diags
+                    (>= severity (warning-numeric-level :warning)))
+           collect `(:propertize
+                     ,(format "%d" (length diags))
+                     face ,face
+                     mouse-face mode-line-highlight
+                     keymap
+                     ,(let ((map (make-sparse-keymap))
+                            (type type))
+                        (define-key map [mode-line mouse-4]
+                          (lambda (_event)
+                            (interactive "e")
+                            (flymake-goto-prev-error 1 (list type) t)))
+                        (define-key map [mode-line mouse-5]
+                          (lambda (_event)
+                            (interactive "e")
+                            (flymake-goto-next-error 1 (list type) t)))
+                        map)
+                     help-echo
+                     ,(concat (format "%s diagnostics of type %s\n"
+                                      (propertize (format "%d"
+                                                          (length diags))
+                                                  'face face)
+                                      (propertize (format "%s" type)
+                                                  'face face))
+                              "mouse-4/mouse-5: previous/next of this type\n"))
+           into forms
+           finally return
+           `((:propertize "[")
+             ,@(cl-loop for (a . rest) on forms by #'cdr
+                        collect a when rest collect
+                        '(:propertize " "))
+             (:propertize "]")))))))
 
 (provide 'flymake)
+
+(require 'flymake-proc)
+
 ;;; flymake.el ends here
diff --git a/test/lisp/progmodes/flymake-resources/Makefile 
b/test/lisp/progmodes/flymake-resources/Makefile
index 0f3f397..4944075 100644
--- a/test/lisp/progmodes/flymake-resources/Makefile
+++ b/test/lisp/progmodes/flymake-resources/Makefile
@@ -1,6 +1,6 @@
 # Makefile for flymake tests
 
-CC_OPTS = -Wall
+CC_OPTS = -Wall -Wextra
 
 ## Recent gcc (e.g. 4.8.2 on RHEL7) can automatically colorize their output,
 ## which can confuse flymake.  Set GCC_COLORS to disable that.
@@ -8,6 +8,6 @@ CC_OPTS = -Wall
 ## normally use flymake, so it seems like just avoiding the issue
 ## in this test is fine.  Set flymake-log-level to 3 to investigate.
 check-syntax:
-       GCC_COLORS= $(CC) $(CC_OPTS) ${CHK_SOURCES}
+       GCC_COLORS= $(CC) $(CC_OPTS) ${CHK_SOURCES} || true
 
 # eof
diff --git a/test/lisp/progmodes/flymake-resources/errors-and-warnings.c 
b/test/lisp/progmodes/flymake-resources/errors-and-warnings.c
new file mode 100644
index 0000000..1d38bd6
--- /dev/null
+++ b/test/lisp/progmodes/flymake-resources/errors-and-warnings.c
@@ -0,0 +1,13 @@
+/* Flymake should notice an error on the next line, since
+   that file has at least one warning.*/
+#include "some-problems.h"
+/* But not this one */
+#include "no-problems.h"
+
+int main()
+{
+  char c = 1000; /* a note and a warning */
+  int bla;
+  char c; if (bla == (void*)3); /* an error, and two warnings */
+  return c;
+}
diff --git a/test/lisp/progmodes/flymake-resources/no-problems.h 
b/test/lisp/progmodes/flymake-resources/no-problems.h
new file mode 100644
index 0000000..19ddc61
--- /dev/null
+++ b/test/lisp/progmodes/flymake-resources/no-problems.h
@@ -0,0 +1 @@
+typedef int no_problems;
diff --git a/test/lisp/progmodes/flymake-resources/some-problems.h 
b/test/lisp/progmodes/flymake-resources/some-problems.h
new file mode 100644
index 0000000..165d8dd
--- /dev/null
+++ b/test/lisp/progmodes/flymake-resources/some-problems.h
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+strange;
+
+sint main();
diff --git a/test/lisp/progmodes/flymake-tests.el 
b/test/lisp/progmodes/flymake-tests.el
index b04346f..5e042f2 100644
--- a/test/lisp/progmodes/flymake-tests.el
+++ b/test/lisp/progmodes/flymake-tests.el
@@ -1,4 +1,4 @@
-;;; flymake-tests.el --- Test suite for flymake
+;;; flymake-tests.el --- Test suite for flymake -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2011-2017 Free Software Foundation, Inc.
 
@@ -26,54 +26,295 @@
 (require 'flymake)
 
 (defvar flymake-tests-data-directory
-  (expand-file-name "lisp/progmodes/flymake-resources" (getenv 
"EMACS_TEST_DIRECTORY"))
+  (expand-file-name "lisp/progmodes/flymake-resources"
+                    (or (getenv "EMACS_TEST_DIRECTORY")
+                        (expand-file-name "../../.."
+                                          (or load-file-name
+                                              buffer-file-name))))
   "Directory containing flymake test data.")
 
 
-;; Warning predicate
-(defun flymake-tests--current-face (file predicate)
-  (let ((buffer (find-file-noselect
-                 (expand-file-name file flymake-tests-data-directory)))
-        (process-environment (cons "LC_ALL=C" process-environment))
-        (i 0))
+;;
+;;
+(defun flymake-tests--wait-for-backends ()
+  ;; Weirdness here...  http://debbugs.gnu.org/17647#25
+  ;; ... meaning `sleep-for', and even
+  ;; `accept-process-output', won't suffice as ways to get
+  ;; process filters and sentinels to run, though they do work
+  ;; fine in a non-interactive batch session. The only thing
+  ;; that will indeed unblock pending process output is
+  ;; reading an input event, so, as a workaround, use a dummy
+  ;; `read-event' with a very short timeout.
+  (unless noninteractive (read-event "" nil 0.1))
+  (cl-loop repeat 5
+           for notdone = (cl-set-difference (flymake-running-backends)
+                                            (flymake-reporting-backends))
+           while notdone
+           unless noninteractive do (read-event "" nil 0.1)
+           do (sleep-for (+ 0.5 flymake-no-changes-timeout))
+           finally (when notdone (ert-fail
+                                  (format "Some backends not reporting yet %s"
+                                          notdone)))))
+
+(cl-defun flymake-tests--call-with-fixture (fn file
+                                               &key (severity-predicate
+                                                     nil sev-pred-supplied-p))
+  "Call FN after flymake setup in FILE, using `flymake-proc`.
+SEVERITY-PREDICATE is used to setup
+`flymake-proc-diagnostic-type-pred'"
+  (let* ((file (expand-file-name file flymake-tests-data-directory))
+         (visiting (find-buffer-visiting file))
+         (buffer (or visiting (find-file-noselect file)))
+         (process-environment (cons "LC_ALL=C" process-environment))
+         (warning-minimum-log-level :error))
     (unwind-protect
         (with-current-buffer buffer
-          (setq-local flymake-warning-predicate predicate)
-          (goto-char (point-min))
-          (flymake-mode 1)
-          ;; Weirdness here...  https://debbugs.gnu.org/17647#25
-          (while (and flymake-is-running (< (setq i (1+ i)) 10))
-            (sleep-for (+ 0.5 flymake-no-changes-timeout)))
-          (flymake-goto-next-error)
-          (face-at-point))
-      (and buffer (let (kill-buffer-query-functions) (kill-buffer buffer))))))
+          (save-excursion
+            (when sev-pred-supplied-p
+              (setq-local flymake-proc-diagnostic-type-pred 
severity-predicate))
+            (goto-char (point-min))
+            (unless flymake-mode (flymake-mode 1))
+            (flymake-tests--wait-for-backends)
+            (funcall fn)))
+      (and buffer
+           (not visiting)
+           (let (kill-buffer-query-functions) (kill-buffer buffer))))))
+
+(cl-defmacro flymake-tests--with-flymake ((file &rest args)
+                                          &body body)
+  (declare (indent 1)
+           (debug (sexp &rest form)))
+  `(flymake-tests--call-with-fixture (lambda () ,@body) ,file ,@args))
 
 (ert-deftest warning-predicate-rx-gcc ()
   "Test GCC warning via regexp predicate."
   (skip-unless (and (executable-find "gcc") (executable-find "make")))
-  (should (eq 'flymake-warnline
-              (flymake-tests--current-face "test.c" "^[Ww]arning"))))
+  (flymake-tests--with-flymake
+      ("test.c" :severity-predicate "^[Ww]arning")
+    (flymake-goto-next-error)
+    (should (eq 'flymake-warning
+                (face-at-point)))))
 
 (ert-deftest warning-predicate-function-gcc ()
   "Test GCC warning via function predicate."
   (skip-unless (and (executable-find "gcc") (executable-find "make")))
-  (should (eq 'flymake-warnline
-              (flymake-tests--current-face "test.c"
-               (lambda (msg) (string-match "^[Ww]arning" msg))))))
+  (flymake-tests--with-flymake
+      ("test.c" :severity-predicate
+       (lambda (msg) (string-match "^[Ww]arning" msg)))
+    (flymake-goto-next-error)
+    (should (eq 'flymake-warning
+                (face-at-point)))))
 
 (ert-deftest warning-predicate-rx-perl ()
   "Test perl warning via regular expression predicate."
   (skip-unless (executable-find "perl"))
-  (should (eq 'flymake-warnline
-              (flymake-tests--current-face "test.pl" "^Scalar value"))))
+  (flymake-tests--with-flymake
+      ("test.pl" :severity-predicate "^Scalar value")
+    (flymake-goto-next-error)
+    (should (eq 'flymake-warning
+                (face-at-point)))))
 
 (ert-deftest warning-predicate-function-perl ()
   "Test perl warning via function predicate."
   (skip-unless (executable-find "perl"))
-  (should (eq 'flymake-warnline
-              (flymake-tests--current-face
-               "test.pl"
-               (lambda (msg) (string-match "^Scalar value" msg))))))
+  (flymake-tests--with-flymake
+      ("test.pl" :severity-predicate
+       (lambda (msg) (string-match "^Scalar value" msg)))
+    (flymake-goto-next-error)
+    (should (eq 'flymake-warning
+                (face-at-point)))))
+
+(ert-deftest different-diagnostic-types ()
+  "Test GCC warning via function predicate."
+  (skip-unless (and (executable-find "gcc") (executable-find "make")))
+  (let ((flymake-wrap-around nil))
+    (flymake-tests--with-flymake
+        ("errors-and-warnings.c")
+      (flymake-goto-next-error)
+      (should (eq 'flymake-error (face-at-point)))
+      (flymake-goto-next-error)
+      (should (eq 'flymake-note (face-at-point)))
+      (flymake-goto-next-error)
+      (should (eq 'flymake-warning (face-at-point)))
+      (flymake-goto-next-error)
+      (should (eq 'flymake-error (face-at-point)))
+      (flymake-goto-next-error)
+      (should (eq 'flymake-warning (face-at-point)))
+      (flymake-goto-next-error)
+      (should (eq 'flymake-warning (face-at-point)))
+      (should-error (flymake-goto-next-error nil nil t)))))
+
+(ert-deftest included-c-header-files ()
+  "Test inclusion of .h header files."
+  (skip-unless (and (executable-find "gcc") (executable-find "make")))
+  (let ((flymake-wrap-around nil))
+    (flymake-tests--with-flymake
+        ("some-problems.h")
+      (flymake-goto-next-error)
+      (should (eq 'flymake-warning (face-at-point)))
+      (flymake-goto-next-error)
+      (should (eq 'flymake-error (face-at-point)))
+      (should-error (flymake-goto-next-error nil nil t)))
+    (flymake-tests--with-flymake
+        ("no-problems.h")
+      (should-error (flymake-goto-next-error nil nil t)))))
+
+(defmacro flymake-tests--assert-set (set
+                                     should
+                                     should-not)
+  (declare (indent 1))
+  `(progn
+     ,@(cl-loop
+        for s in should
+        collect `(should (memq (quote ,s) ,set)))
+     ,@(cl-loop
+        for s in should-not
+        collect `(should-not (memq (quote ,s) ,set)))))
+
+(defun flymake-tests--diagnose-words
+    (report-fn type words)
+  "Helper. Call REPORT-FN with diagnostics for WORDS in buffer."
+  (funcall report-fn
+           (cl-loop
+            for word in words
+            append
+            (save-excursion
+              (goto-char (point-min))
+              (cl-loop while (word-search-forward word nil t)
+                       collect (flymake-make-diagnostic
+                                (current-buffer)
+                                (match-beginning 0)
+                                (match-end 0)
+                                type
+                                (concat word " is wrong")))))))
+
+(ert-deftest dummy-backends ()
+  "Test many different kinds of backends."
+  (with-temp-buffer
+    (cl-letf
+        (((symbol-function 'error-backend)
+          (lambda (report-fn)
+            (run-with-timer
+             0.5 nil
+             #'flymake-tests--diagnose-words report-fn :error '("manha" 
"prognata"))))
+         ((symbol-function 'warning-backend)
+          (lambda (report-fn)
+            (run-with-timer
+             0.5 nil
+             #'flymake-tests--diagnose-words report-fn :warning '("ut" 
"dolor"))))
+         ((symbol-function 'sync-backend)
+          (lambda (report-fn)
+            (flymake-tests--diagnose-words report-fn :note '("quis" 
"commodo"))))
+         ((symbol-function 'panicking-backend)
+          (lambda (report-fn)
+            (run-with-timer
+             0.5 nil
+             report-fn :panic :explanation "The spanish inquisition!")))
+         ((symbol-function 'crashing-backend)
+          (lambda (_report-fn)
+            ;; HACK: Shoosh log during tests
+            (setq-local warning-minimum-log-level :emergency)
+            (error "crashed"))))
+      (insert "Lorem ipsum dolor sit amet, consectetur adipiscing
+    elit, sed do eiusmod tempor incididunt ut labore et dolore
+    manha aliqua. Ut enim ad minim veniam, quis nostrud
+    exercitation ullamco laboris nisi ut aliquip ex ea commodo
+    consequat. Duis aute irure dolor in reprehenderit in
+    voluptate velit esse cillum dolore eu fugiat nulla
+    pariatur. Excepteur sint occaecat cupidatat non prognata
+    sunt in culpa qui officia deserunt mollit anim id est
+    laborum.")
+      (let ((flymake-diagnostic-functions
+             (list 'error-backend 'warning-backend 'sync-backend
+                   'panicking-backend
+                   'crashing-backend
+                   ))
+            (flymake-wrap-around nil))
+        (flymake-mode)
+
+        (flymake-tests--assert-set (flymake-running-backends)
+          (error-backend warning-backend panicking-backend)
+          (crashing-backend))
+
+        (flymake-tests--assert-set (flymake-disabled-backends)
+          (crashing-backend)
+          (error-backend warning-backend sync-backend
+                         panicking-backend))
+
+        (flymake-tests--wait-for-backends)
+
+        (flymake-tests--assert-set (flymake-disabled-backends)
+          (crashing-backend panicking-backend)
+          (error-backend warning-backend sync-backend))
+
+        (goto-char (point-min))
+        (flymake-goto-next-error)
+        (should (eq 'flymake-warning (face-at-point))) ; dolor
+        (flymake-goto-next-error)
+        (should (eq 'flymake-warning (face-at-point))) ; ut
+        (flymake-goto-next-error)
+        (should (eq 'flymake-error (face-at-point))) ; manha
+        (flymake-goto-next-error)
+        (should (eq 'flymake-warning (face-at-point))) ; Ut
+        (flymake-goto-next-error)
+        (should (eq 'flymake-note (face-at-point))) ; quis
+        (flymake-goto-next-error)
+        (should (eq 'flymake-warning (face-at-point))) ; ut
+        (flymake-goto-next-error)
+        (should (eq 'flymake-note (face-at-point))) ; commodo
+        (flymake-goto-next-error)
+        (should (eq 'flymake-warning (face-at-point))) ; dolor
+        (flymake-goto-next-error)
+        (should (eq 'flymake-error (face-at-point))) ; prognata
+        (should-error (flymake-goto-next-error nil nil t))))))
+
+(ert-deftest recurrent-backend ()
+  "Test a backend that calls REPORT-FN multiple times"
+  (with-temp-buffer
+    (let (tick)
+      (cl-letf
+          (((symbol-function 'eager-backend)
+            (lambda (report-fn)
+              (funcall report-fn nil :explanation "very eager but no 
diagnostics")
+              (display-buffer (current-buffer))
+              (run-with-timer
+               0.5 nil
+               (lambda ()
+                 (flymake-tests--diagnose-words report-fn :warning 
'("consectetur"))
+                 (setq tick t)
+                 (run-with-timer
+                  0.5 nil
+                  (lambda ()
+                    (flymake-tests--diagnose-words report-fn :error 
'("fugiat"))
+                    (setq tick t))))))))
+        (insert "Lorem ipsum dolor sit amet, consectetur adipiscing
+    elit, sed do eiusmod tempor incididunt ut labore et dolore
+    manha aliqua. Ut enim ad minim veniam, quis nostrud
+    exercitation ullamco laboris nisi ut aliquip ex ea commodo
+    consequat. Duis aute irure dolor in reprehenderit in
+    voluptate velit esse cillum dolore eu fugiat nulla
+    pariatur. Excepteur sint occaecat cupidatat non prognata
+    sunt in culpa qui officia deserunt mollit anim id est
+    laborum.")
+        (let ((flymake-diagnostic-functions
+               (list 'eager-backend))
+              (flymake-wrap-around nil))
+          (flymake-mode)
+          (flymake-tests--assert-set (flymake-running-backends)
+            (eager-backend) ())
+          (cl-loop until tick repeat 4 do (sleep-for 0.2))
+          (setq tick nil)
+          (goto-char (point-max))
+          (flymake-goto-prev-error)
+          (should (eq 'flymake-warning (face-at-point))) ; consectetur
+          (should-error (flymake-goto-prev-error nil nil t))
+          (cl-loop until tick repeat 4 do (sleep-for 0.2))
+          (flymake-goto-next-error)
+          (should (eq 'flymake-error (face-at-point))) ; fugiat
+          (flymake-goto-prev-error)
+          (should (eq 'flymake-warning (face-at-point))) ; back at consectetur
+          (should-error (flymake-goto-prev-error nil nil t))
+          )))))
 
 (provide 'flymake-tests)
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]