From 9a768d7f3e1dbaf17a667ec47d7216a2836cbcdf Mon Sep 17 00:00:00 2001 From: Sebastiaan Speck Date: Sat, 16 Nov 2024 16:17:38 +0100 Subject: [PATCH] Add the possibility to show the default values for parameters --- CHANGES.md | 1 + .../sw/magik/checks/MagikCheckHolder.java | 24 ++++++- .../checks/MagikChecksConfiguration.java | 41 ++++++------ .../ramsolutions/sw/magik/lint/MagikLint.java | 66 +++++++++++++++---- .../nl/ramsolutions/sw/magik/lint/Main.java | 65 +++++++++++------- .../sw/magik/typedlint/MagikTypedLint.java | 66 +++++++++++++++---- .../ramsolutions/sw/magik/typedlint/Main.java | 58 ++++++++++------ 7 files changed, 230 insertions(+), 91 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a9ae16361..91b13f00a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,6 +24,7 @@ - Add `.sys!perform()` and `.sys!slot()` to ForbiddenCallCheck. - Do not check abstract method parameters in UnusedVariableCheck if `check-parameters`. - Fix sslr-magik-toolkit's "Evaluate XPath"-button. +- Add `--with-default-values` option to `magik-lint`/`magik-typed-lint` to show the default values for parameters. - Several fixes. ## Breaking changes (reiterated from above) diff --git a/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikCheckHolder.java b/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikCheckHolder.java index 883b8b089..1463fa362 100644 --- a/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikCheckHolder.java +++ b/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikCheckHolder.java @@ -21,6 +21,7 @@ public static class Parameter { private final String name; private final String description; private final Object value; + private final Object defaultValue; /** * Constructor. @@ -28,24 +29,43 @@ public static class Parameter { * @param name Name of parameter. * @param description Description of parameter. * @param value Value of parameter. + * @param defaultValue Default value of parameter. */ - public Parameter(final String name, final String description, final @Nullable Object value) { + public Parameter( + final String name, + final String description, + final @Nullable Object value, + final @Nullable Object defaultValue) { this.name = name; this.description = description; this.value = value; + this.defaultValue = defaultValue; } public String getName() { return this.name; } + public String getNameWithoutCheckName() { + return this.name.split("\\.")[1]; + } + public String getDescription() { return this.description; } @CheckForNull public Object getValue() { - return this.value; + return this.value != null ? this.value : this.defaultValue; + } + + @CheckForNull + public Object getDefaultValue() { + return this.defaultValue; + } + + public boolean isExplicitlySet() { + return this.value != null; } } diff --git a/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikChecksConfiguration.java b/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikChecksConfiguration.java index 7e1c30415..195e4e5dd 100644 --- a/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikChecksConfiguration.java +++ b/magik-checks/src/main/java/nl/ramsolutions/sw/magik/checks/MagikChecksConfiguration.java @@ -62,31 +62,28 @@ public List getAllChecks() { ruleProperty -> { final String propertyKey = MagikChecksConfiguration.propertyKey(ruleProperty); final String configKey = checkKey + "." + propertyKey; - if (!this.properties.hasProperty(configKey)) { - return null; - } - - // Store parameter. final String description = ruleProperty.description(); - final MagikCheckHolder.Parameter parameter; - if (ruleProperty.type().equals("INTEGER")) { - final Integer configValue = this.properties.getPropertyInteger(configKey); - parameter = - new MagikCheckHolder.Parameter(configKey, description, configValue); - } else if (ruleProperty.type().equals("STRING")) { - final String configValue = this.properties.getPropertyString(configKey); - parameter = - new MagikCheckHolder.Parameter(configKey, description, configValue); - } else if (ruleProperty.type().equals("BOOLEAN")) { - final Boolean configValue = this.properties.getPropertyBoolean(configKey); - parameter = - new MagikCheckHolder.Parameter(configKey, description, configValue); - } else { - throw new IllegalStateException( - "Unknown type for property: " + ruleProperty.type()); + Object configValue = null; + Object defaultValue = ruleProperty.defaultValue(); + + // Get configured value if it exists + if (this.properties.hasProperty(configKey)) { + if (ruleProperty.type().equals("INTEGER")) { + configValue = this.properties.getPropertyInteger(configKey); + defaultValue = Integer.parseInt(ruleProperty.defaultValue()); + } else if (ruleProperty.type().equals("STRING")) { + configValue = this.properties.getPropertyString(configKey); + } else if (ruleProperty.type().equals("BOOLEAN")) { + configValue = this.properties.getPropertyBoolean(configKey); + defaultValue = Boolean.parseBoolean(ruleProperty.defaultValue()); + } else { + throw new IllegalStateException( + "Unknown type for property: " + ruleProperty.type()); + } } - return parameter; + return new MagikCheckHolder.Parameter( + configKey, description, configValue, defaultValue); }) .filter(Objects::nonNull) .collect(Collectors.toSet()); diff --git a/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/MagikLint.java b/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/MagikLint.java index 6efffafb0..872e10332 100644 --- a/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/MagikLint.java +++ b/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/MagikLint.java @@ -86,14 +86,15 @@ private List runCheckOnFile(final MagikFile magikFile, final MagikCh } /** - * Show checks active and inactive checks. + * Show enabled and disabled checks. * * @param writer Writer Write to write output to. * @param showDisabled boolean Boolean to show disabled checks or not. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. * @throws ReflectiveOperationException - * @throws IOException - */ - void showChecks(final Writer writer, final boolean showDisabled) + void showChecks(final Writer writer, final boolean showDisabled, boolean showDefaultValues) throws ReflectiveOperationException, IOException { final MagikChecksConfiguration checksConfig = new MagikChecksConfiguration(CheckList.getChecks(), this.properties); @@ -106,14 +107,51 @@ void showChecks(final Writer writer, final boolean showDisabled) continue; } - for (final MagikCheckHolder.Parameter parameter : holder.getParameters()) { + showParameters(writer, holder, showDefaultValues); + } + } + + /** + * Show parameters for a check. + * + * @param writer Writer Write to write output to. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. + * @throws ReflectiveOperationException - + * @throws IOException - + */ + private void showParameters( + final Writer writer, final MagikCheckHolder holder, final boolean showDefaultValues) + throws ReflectiveOperationException, IOException { + for (final MagikCheckHolder.Parameter parameter : holder.getParameters()) { + if (!parameter.isExplicitlySet() && !showDefaultValues) { + continue; + } + final String defaultIndicator = !parameter.isExplicitlySet() ? " (default)" : ""; + // Handle comma-separated list parameters differently + if (parameter.getValue() != null && parameter.getValue().toString().contains(",")) { writer.write( - "\t" - + parameter.getName() - + ":\t" - + parameter.getValue() + " ".repeat(2) + + "*" + + defaultIndicator + + " " + + parameter.getNameWithoutCheckName() + + " (" + + parameter.getDescription() + + "):\n"); + String[] values = parameter.getValue().toString().split(","); + for (String value : values) { + writer.write(" ".repeat(4) + "- " + value.trim() + "\n"); + } + } else { + writer.write( + " ".repeat(2) + + "*" + + defaultIndicator + " " - + "(" + + parameter.getNameWithoutCheckName() + + ": " + + parameter.getValue() + + " (" + parameter.getDescription() + ")\n"); } @@ -124,24 +162,28 @@ void showChecks(final Writer writer, final boolean showDisabled) * Show enabled checks. * * @param writer Writer Write to write output to. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. * @throws ReflectiveOperationException - * @throws IOException - */ - void showEnabledChecks(final Writer writer) throws ReflectiveOperationException, IOException { + void showEnabledChecks(final Writer writer, final Boolean showDefaultValues) + throws ReflectiveOperationException, IOException { writer.write("Enabled checks:\n"); - this.showChecks(writer, false); + this.showChecks(writer, false, showDefaultValues); } /** * Show disabled checks. * * @param writer Writer Write to write output to. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. * @throws ReflectiveOperationException - * @throws IOException - */ - void showDisabledChecks(final Writer writer) throws ReflectiveOperationException, IOException { + void showDisabledChecks(final Writer writer, final boolean showDefaultValues) + throws ReflectiveOperationException, IOException { writer.write("Disabled checks:\n"); - this.showChecks(writer, true); + this.showChecks(writer, true, showDefaultValues); } /** diff --git a/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/Main.java b/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/Main.java index f131b1387..a1114c7d9 100644 --- a/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/Main.java +++ b/magik-lint/src/main/java/nl/ramsolutions/sw/magik/lint/Main.java @@ -50,6 +50,11 @@ public final class Main { .build(); private static final Option OPTION_SHOW_CHECKS = Option.builder().longOpt("show-checks").desc("Show checks and exit").build(); + private static final Option OPTION_WITH_DEFAULT_VALUES = + Option.builder() + .longOpt("with-default-values") + .desc("Show default values when showing checks") + .build(); private static final Option OPTION_COLUMN_OFFSET = Option.builder() .longOpt("column-offset") @@ -64,14 +69,15 @@ public final class Main { .hasArg() .type(PatternOptionBuilder.NUMBER_VALUE) .build(); + private static final Option OPTION_APPLY_FIXES = + Option.builder().longOpt("apply-fixes").desc("Apply fixes automatically").build(); + private static final Option OPTION_DEBUG = Option.builder().longOpt("debug").desc("Enable showing of debug information").build(); private static final Option OPTION_VERSION = Option.builder().longOpt("version").desc("Show version and exit").build(); private static final Option OPTION_HELP = Option.builder().longOpt("help").desc("Show this help and exit").build(); - private static final Option OPTION_APPLY_FIXES = - Option.builder().longOpt("apply-fixes").desc("Apply fixes automatically").build(); static { OPTIONS = new Options(); @@ -79,11 +85,12 @@ public final class Main { OPTIONS.addOption(OPTION_MSG_TEMPLATE); OPTIONS.addOption(OPTION_RCFILE); OPTIONS.addOption(OPTION_SHOW_CHECKS); + OPTIONS.addOption(OPTION_WITH_DEFAULT_VALUES); OPTIONS.addOption(OPTION_COLUMN_OFFSET); OPTIONS.addOption(OPTION_MAX_INFRACTIONS); + OPTIONS.addOption(OPTION_APPLY_FIXES); OPTIONS.addOption(OPTION_DEBUG); OPTIONS.addOption(OPTION_VERSION); - OPTIONS.addOption(OPTION_APPLY_FIXES); } private static final Map SEVERITY_EXIT_CODE_MAPPING = @@ -175,6 +182,13 @@ public static void main(final String[] args) Main.initDebugLogger(); } + if (commandLine.hasOption(OPTION_WITH_DEFAULT_VALUES) + && !commandLine.hasOption(OPTION_SHOW_CHECKS)) { + final PrintStream errStream = Main.getErrStream(); + errStream.println("--with-default-values can only be used with --show-checks"); + System.exit(1); + } + if (commandLine.hasOption(OPTION_VERSION)) { final String version = Main.class.getPackage().getImplementationVersion(); final PrintStream errStream = Main.getErrStream(); @@ -183,24 +197,7 @@ public static void main(final String[] args) } // Read configuration. - final MagikToolsProperties properties; - if (commandLine.hasOption(OPTION_RCFILE)) { - final File rcfile = (File) commandLine.getParsedOptionValue(OPTION_RCFILE); - final Path path = rcfile.toPath(); - if (!Files.exists(path)) { - final PrintStream errStream = Main.getErrStream(); - errStream.println("RC File does not exist: " + path); - - System.exit(1); - } - properties = new MagikToolsProperties(path); - } else { - final Path currentWorkingPath = Path.of("."); - final Path path = ConfigurationLocator.locateConfiguration(currentWorkingPath); - properties = - path != null ? new MagikToolsProperties(path) : MagikToolsProperties.DEFAULT_PROPERTIES; - } - + final MagikToolsProperties properties = Main.loadProperties(commandLine); // Copy configuration from command line. Main.copyOptionsToConfig(commandLine, properties); @@ -210,8 +207,9 @@ public static void main(final String[] args) final MagikLint lint = new MagikLint(properties, reporter); final PrintStream outStream = Main.getOutStream(); final Writer writer = new PrintWriter(outStream); - lint.showEnabledChecks(writer); - lint.showDisabledChecks(writer); + final boolean showDefaultValues = commandLine.hasOption(OPTION_WITH_DEFAULT_VALUES); + lint.showEnabledChecks(writer, showDefaultValues); + lint.showDisabledChecks(writer, showDefaultValues); writer.flush(); System.exit(0); } @@ -246,6 +244,27 @@ public static void main(final String[] args) System.exit(exitCode); } + private static MagikToolsProperties loadProperties(final CommandLine commandLine) + throws ParseException, IOException { + if (commandLine.hasOption(OPTION_RCFILE)) { + final File rcfile = (File) commandLine.getParsedOptionValue(OPTION_RCFILE); + final Path path = rcfile.toPath(); + if (!Files.exists(path)) { + final PrintStream errStream = Main.getErrStream(); + errStream.println("RC File does not exist: " + path); + + System.exit(1); + } + return new MagikToolsProperties(path); + } else { + final Path currentWorkingPath = Path.of("."); + final Path path = ConfigurationLocator.locateConfiguration(currentWorkingPath); + return path != null + ? new MagikToolsProperties(path) + : MagikToolsProperties.DEFAULT_PROPERTIES; + } + } + private static void copyOptionsToConfig( final CommandLine commandLine, final MagikToolsProperties properties) { if (commandLine.hasOption(OPTION_MAX_INFRACTIONS)) { diff --git a/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/MagikTypedLint.java b/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/MagikTypedLint.java index 40808aecb..1bdd15f15 100644 --- a/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/MagikTypedLint.java +++ b/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/MagikTypedLint.java @@ -95,14 +95,15 @@ private List runCheckOnFile( } /** - * Show checks active and inactive checks. + * Show enabled and disabled checks. * * @param writer Writer Write to write output to. * @param showDisabled boolean Boolean to show disabled checks or not. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. * @throws ReflectiveOperationException - * @throws IOException - */ - void showChecks(final Writer writer, final boolean showDisabled) + void showChecks(final Writer writer, final boolean showDisabled, boolean showDefaultValues) throws ReflectiveOperationException, IOException { final MagikChecksConfiguration checksConfig = new MagikChecksConfiguration(CheckList.getChecks(), this.properties); @@ -115,14 +116,51 @@ void showChecks(final Writer writer, final boolean showDisabled) continue; } - for (final MagikCheckHolder.Parameter parameter : holder.getParameters()) { + showParameters(writer, holder, showDefaultValues); + } + } + + /** + * Show parameters for a check. + * + * @param writer Writer Write to write output to. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. + * @throws ReflectiveOperationException - + * @throws IOException - + */ + private void showParameters( + final Writer writer, final MagikCheckHolder holder, final boolean showDefaultValues) + throws ReflectiveOperationException, IOException { + for (final MagikCheckHolder.Parameter parameter : holder.getParameters()) { + if (!parameter.isExplicitlySet() && !showDefaultValues) { + continue; + } + final String defaultIndicator = !parameter.isExplicitlySet() ? " (default)" : ""; + // Handle comma-separated list parameters differently + if (parameter.getValue() != null && parameter.getValue().toString().contains(",")) { writer.write( - "\t" - + parameter.getName() - + ":\t" - + parameter.getValue() + " ".repeat(2) + + "*" + + defaultIndicator + + " " + + parameter.getNameWithoutCheckName() + + " (" + + parameter.getDescription() + + "):\n"); + String[] values = parameter.getValue().toString().split(","); + for (String value : values) { + writer.write(" ".repeat(4) + "- " + value.trim() + "\n"); + } + } else { + writer.write( + " ".repeat(2) + + "*" + + defaultIndicator + " " - + "(" + + parameter.getNameWithoutCheckName() + + ": " + + parameter.getValue() + + " (" + parameter.getDescription() + ")\n"); } @@ -133,24 +171,28 @@ void showChecks(final Writer writer, final boolean showDisabled) * Show enabled checks. * * @param writer Writer Write to write output to. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. * @throws ReflectiveOperationException - * @throws IOException - */ - void showEnabledChecks(final Writer writer) throws ReflectiveOperationException, IOException { + void showEnabledChecks(final Writer writer, final Boolean showDefaultValues) + throws ReflectiveOperationException, IOException { writer.write("Enabled checks:\n"); - this.showChecks(writer, false); + this.showChecks(writer, false, showDefaultValues); } /** * Show disabled checks. * * @param writer Writer Write to write output to. + * @param showDefaultValues boolean Boolean to show default values for parameters or not. * @throws ReflectiveOperationException - * @throws IOException - */ - void showDisabledChecks(final Writer writer) throws ReflectiveOperationException, IOException { + void showDisabledChecks(final Writer writer, final boolean showDefaultValues) + throws ReflectiveOperationException, IOException { writer.write("Disabled checks:\n"); - this.showChecks(writer, true); + this.showChecks(writer, true, showDefaultValues); } /** diff --git a/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/Main.java b/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/Main.java index cffed8d6b..0905f6772 100644 --- a/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/Main.java +++ b/magik-typed-lint/src/main/java/nl/ramsolutions/sw/magik/typedlint/Main.java @@ -56,6 +56,11 @@ public final class Main { .build(); private static final Option OPTION_SHOW_CHECKS = Option.builder().longOpt("show-checks").desc("Show checks and exit").build(); + private static final Option OPTION_WITH_DEFAULT_VALUES = + Option.builder() + .longOpt("with-default-values") + .desc("Show default values for parameters when showing checks") + .build(); private static final Option OPTION_COLUMN_OFFSET = Option.builder() .longOpt("column-offset") @@ -97,6 +102,7 @@ public final class Main { OPTIONS.addOption(OPTION_MSG_TEMPLATE); OPTIONS.addOption(OPTION_RCFILE); OPTIONS.addOption(OPTION_SHOW_CHECKS); + OPTIONS.addOption(OPTION_WITH_DEFAULT_VALUES); OPTIONS.addOption(OPTION_COLUMN_OFFSET); OPTIONS.addOption(OPTION_MAX_INFRACTIONS); OPTIONS.addOption(OPTION_TYPE_DATABASE); @@ -219,6 +225,13 @@ public static void main(final String[] args) Main.initDebugLogger(); } + if (commandLine.hasOption(OPTION_WITH_DEFAULT_VALUES) + && !commandLine.hasOption(OPTION_SHOW_CHECKS)) { + final PrintStream errStream = Main.getErrStream(); + errStream.println("--with-default-values can only be used with --show-checks"); + System.exit(1); + } + if (commandLine.hasOption(OPTION_VERSION)) { final String version = Main.class.getPackage().getImplementationVersion(); final PrintStream errStream = Main.getErrStream(); @@ -227,24 +240,7 @@ public static void main(final String[] args) } // Read configuration. - final MagikToolsProperties properties; - if (commandLine.hasOption(OPTION_RCFILE)) { - final File rcfile = (File) commandLine.getParsedOptionValue(OPTION_RCFILE); - final Path path = rcfile.toPath(); - if (!Files.exists(path)) { - final PrintStream errStream = Main.getErrStream(); - errStream.println("RC File does not exist: " + path); - - System.exit(1); - } - properties = new MagikToolsProperties(path); - } else { - final Path currentWorkingPath = Path.of(""); - final Path path = ConfigurationLocator.locateConfiguration(currentWorkingPath); - properties = - path != null ? new MagikToolsProperties(path) : MagikToolsProperties.DEFAULT_PROPERTIES; - } - + final MagikToolsProperties properties = Main.loadProperties(commandLine); // Copy configuration from command line. Main.copyOptionsToConfig(commandLine, properties); @@ -255,8 +251,9 @@ public static void main(final String[] args) final MagikTypedLint lint = new MagikTypedLint(definitionKeeper, properties, reporter); final PrintStream outStream = Main.getOutStream(); final Writer writer = new PrintWriter(outStream); - lint.showEnabledChecks(writer); - lint.showDisabledChecks(writer); + final boolean showDefaultValues = commandLine.hasOption(OPTION_WITH_DEFAULT_VALUES); + lint.showEnabledChecks(writer, showDefaultValues); + lint.showDisabledChecks(writer, showDefaultValues); writer.flush(); System.exit(0); } @@ -298,6 +295,27 @@ public static void main(final String[] args) System.exit(exitCode); } + private static MagikToolsProperties loadProperties(final CommandLine commandLine) + throws ParseException, IOException { + if (commandLine.hasOption(OPTION_RCFILE)) { + final File rcfile = (File) commandLine.getParsedOptionValue(OPTION_RCFILE); + final Path path = rcfile.toPath(); + if (!Files.exists(path)) { + final PrintStream errStream = Main.getErrStream(); + errStream.println("RC File does not exist: " + path); + + System.exit(1); + } + return new MagikToolsProperties(path); + } else { + final Path currentWorkingPath = Path.of("."); + final Path path = ConfigurationLocator.locateConfiguration(currentWorkingPath); + return path != null + ? new MagikToolsProperties(path) + : MagikToolsProperties.DEFAULT_PROPERTIES; + } + } + private static void copyOptionsToConfig( final CommandLine commandLine, final MagikToolsProperties properties) { if (commandLine.hasOption(OPTION_MAX_INFRACTIONS)) {