# The human-readable description of the message.
#
- # It should be short and fit on a single line.
- # It should also have meaningful information first in case
- # on truncation by an IDE for instance.
+ # eg. "Error: cannot find method `foo`."
+ #
+ # A good message should:
+ #
+ # * start with a message type like "Error:", "Syntax Error:", "Warning:".
+ # The type is capitalized and terminated by a column.
+ # The rest on the message starts with a lowercase letter and is terminated with a dot.
+ #
+ # * be short and fit on a single line.
+ #
+ # * have meaningful information first.
+ # This helps the reader and remain usable
+ # when truncated, by an IDE for instance.
+ #
+ # * enclose identifiers, keywords and pieces of code with back-quotes.
var text: String
# Comparisons are made on message locations.
return location.as(not null) < other.location.as(not null)
end
+ redef fun ==(other): Bool do
+ if not other isa Message then return false
+ return location == other.location and tag == other.tag and text == other.text
+ end
+
redef fun to_s: String
do
var l = location
end
end
+redef class Location
+ # Errors and warnings associated to this location.
+ var messages: nullable Array[Message]
+
+ # Add a message to `self`
+ #
+ # See `messages`
+ private fun add_message(m: Message)
+ do
+ var ms = messages
+ if ms == null then
+ ms = new Array[Message]
+ messages = ms
+ end
+ ms.add m
+ end
+end
+
# Global context for tools
class ToolContext
# Number of errors
return tags.has("all") or tags.has(tag)
end
- # Output all current stacked messages and display total error informations
+ # Output all current stacked messages
#
# Return true if no errors occurred.
#
# If some errors occurred, the behavior depends on the value of `keep_going`.
- # If `keep_going` is false, then the program exits.
- # Else, the error count and the warning count are reset and false is returned.
+ # If `keep_going` is false, then the total error informations is displayed and the program exits.
+ # Else, false is returned.
fun check_errors: Bool
do
if messages.length > 0 then
end
if error_count > 0 then
- errors_info
- if not keep_going then exit(1)
+ if not keep_going then
+ errors_info
+ exit(1)
+ end
return false
end
return true
end
- # Display (and reset) total error informations
+ # Display total error informations
fun errors_info
do
if error_count == 0 and warning_count == 0 then return
if opt_no_color.value then return
sys.stderr.write "Errors: {error_count}. Warnings: {warning_count}.\n"
- error_count = 0
- warning_count = 0
end
# Display an error
- fun error(l: nullable Location, s: String)
+ #
+ # Return the message (to add information)
+ fun error(l: nullable Location, s: String): Message
do
- messages.add(new Message(l,null,s))
+ var m = new Message(l,null,s)
+ if messages.has(m) then return m
+ if l != null then l.add_message m
+ messages.add m
error_count = error_count + 1
if opt_stop_on_first_error.value then check_errors
+ return m
end
# Add an error, show errors and quit
+ #
+ # Because the program will quit, nothing is returned.
fun fatal_error(l: nullable Location, s: String)
do
error(l,s)
# * They always are real issues (no false positive)
#
# First-level warnings are displayed by default (except if option `-q` is given).
- fun warning(l: nullable Location, tag: String, text: String)
+ #
+ # Return the message (to add information) or null if the warning is disabled
+ fun warning(l: nullable Location, tag: String, text: String): nullable Message
do
- if opt_warning.value.has("no-{tag}") then return
- if not opt_warning.value.has(tag) and opt_warn.value == 0 then return
- if is_warning_blacklisted(l, tag) then return
- messages.add(new Message(l, tag, text))
+ if opt_warning.value.has("no-{tag}") then return null
+ if not opt_warning.value.has(tag) and opt_warn.value == 0 then return null
+ if is_warning_blacklisted(l, tag) then return null
+ var m = new Message(l, tag, text)
+ if messages.has(m) then return null
+ if l != null then l.add_message m
+ messages.add m
warning_count = warning_count + 1
if opt_stop_on_first_error.value then check_errors
+ return m
end
# Display a second-level warning.
#
# In order to prevent warning inflation à la Java, second-level warnings are not displayed by
# default and require an additional option `-W`.
- fun advice(l: nullable Location, tag: String, text: String)
+ #
+ # Return the message (to add information) or null if the warning is disabled
+ fun advice(l: nullable Location, tag: String, text: String): nullable Message
do
- if opt_warning.value.has("no-{tag}") then return
- if not opt_warning.value.has(tag) and opt_warn.value <= 1 then return
- if is_warning_blacklisted(l, tag) then return
- messages.add(new Message(l, tag, text))
+ if opt_warning.value.has("no-{tag}") then return null
+ if not opt_warning.value.has(tag) and opt_warn.value <= 1 then return null
+ if is_warning_blacklisted(l, tag) then return null
+ var m = new Message(l, tag, text)
+ if messages.has(m) then return null
+ if l != null then l.add_message m
+ messages.add m
warning_count = warning_count + 1
if opt_stop_on_first_error.value then check_errors
+ return m
end
# Display an info
# Option --stop-on-first-error
var opt_stop_on_first_error = new OptionBool("Stop on first error", "--stop-on-first-error")
+ # Option --keep-going
+ var opt_keep_going = new OptionBool("Continue after errors, whatever the consequences", "--keep-going")
+
# Option --no-color
var opt_no_color = new OptionBool("Do not use color to display errors and warnings", "--no-color")
init
do
- option_context.add_option(opt_warn, opt_warning, opt_quiet, opt_stop_on_first_error, opt_no_color, opt_log, opt_log_dir, opt_nit_dir, opt_help, opt_version, opt_set_dummy_tool, opt_verbose, opt_bash_completion, opt_stub_man)
+ option_context.add_option(opt_warn, opt_warning, opt_quiet, opt_stop_on_first_error, opt_keep_going, opt_no_color, opt_log, opt_log_dir, opt_nit_dir, opt_help, opt_version, opt_set_dummy_tool, opt_verbose, opt_bash_completion, opt_stub_man)
# Hide some internal options
opt_stub_man.hidden = true
# Set verbose level
verbose_level = opt_verbose.value
+ if opt_keep_going.value then keep_going = true
+
if self.opt_quiet.value then self.opt_warn.value = 0
if opt_log_dir.value != null then log_directory = opt_log_dir.value.as(not null)
var res = opt_nit_dir.value
if res != null then
if not check_nit_dir(res) then
- fatal_error(null, "Fatal Error: the value of --nit-dir does not seem to be a valid base Nit directory: {res}")
+ fatal_error(null, "Fatal Error: the value of --nit-dir does not seem to be a valid base Nit directory: {res}.")
end
return res
end
res = "NIT_DIR".environ
if not res.is_empty then
if not check_nit_dir(res) then
- fatal_error(null, "Fatal Error: the value of NIT_DIR does not seem to be a valid base Nit directory: {res}")
+ fatal_error(null, "Fatal Error: the value of NIT_DIR does not seem to be a valid base Nit directory: {res}.")
end
return res
end
if check_nit_dir(res) then return res.simplify_path
end
- fatal_error(null, "Fatal Error: Cannot locate a valid base nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option.")
+ fatal_error(null, "Fatal Error: cannot locate a valid base Nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option.")
abort
end
#
# On some Linux systems `bash_completion` allow the program to control command line behaviour.
#
-# $ nitls [TAB][TAB]
-# file1.nit file2.nit file3.nit
+# ~~~sh
+# $ nitls [TAB][TAB]
+# file1.nit file2.nit file3.nit
#
-# $ nitls --[TAB][TAB]
-# --bash-toolname --keep --path --tree
-# --depends --log --project --verbose
-# --disable-phase --log-dir --quiet --version
-# --gen-bash-completion --no-color --recursive --warn
-# --help --only-metamodel --source
-# --ignore-visibility --only-parse --stop-on-first-error
+# $ nitls --[TAB][TAB]
+# --bash-toolname --keep --path --tree
+# --depends --log --project --verbose
+# --disable-phase --log-dir --quiet --version
+# --gen-bash-completion --no-color --recursive --warn
+# --help --only-metamodel --source
+# --ignore-visibility --only-parse --stop-on-first-error
+# ~~~
#
# Generated file can be placed in system bash_completion directory `/etc/bash_completion.d/`
# or source it in `~/.bash_completion`.