From f9e0c41e87e196aa2d28d467bd312b850303d25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Tue, 13 Jan 2026 15:54:50 +0100 Subject: [PATCH 1/8] Use conventional type style --- src/jurand_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jurand_test.cpp b/src/jurand_test.cpp index af8abaf..2fa5e16 100644 --- a/src/jurand_test.cpp +++ b/src/jurand_test.cpp @@ -5,8 +5,8 @@ using namespace java_symbols; -template -static std::ostream &operator<<(std::ostream &os, const std::tuple &t) +template +static std::ostream& operator<<(std::ostream& os, const std::tuple& t) { return os << "(" << std::get<0>(t) << ", " << std::get<1>(t) << ")"; } From 7c8a4764d5411bef1d74d603481914e1c30eae6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Thu, 29 Jan 2026 15:28:58 +0100 Subject: [PATCH 2/8] Highlight CLI flag in error output --- src/jurand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jurand.cpp b/src/jurand.cpp index 3775aaa..280f677 100644 --- a/src/jurand.cpp +++ b/src/jurand.cpp @@ -198,7 +198,7 @@ Usage: jurand [optional flags] ... [file path]... if (parameters.also_remove_annotations_ and not strict_mode->any_annotation_removed_.load(std::memory_order_acquire)) { - std::cout << "jurand: strict mode: -a was specified but no annotation was removed" << "\n"; + std::cout << "jurand: strict mode: '-a' was specified but no annotation was removed" << "\n"; exit_code = 3; } } From 804990990526212c4c47f52ae792198f40648d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Thu, 29 Jan 2026 15:27:23 +0100 Subject: [PATCH 3/8] Remove invalid long flags from documentation --- manpages/jurand.1.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manpages/jurand.1.adoc b/manpages/jurand.1.adoc index d447352..c35fdc9 100644 --- a/manpages/jurand.1.adoc +++ b/manpages/jurand.1.adoc @@ -18,10 +18,10 @@ The tool follows Java language rules rather than applying simple regular express Currently the tool is able to remove `import` statements and annotations. == OPTIONS -*-n*, *--name*=__:: +*-n __:: Simple (not fully-qualified) class name. -*-p*, *--pattern*=__:: +*-p __:: Regex pattern to match names used in code. *-a*:: From ae3daa7054c7049b9aa2a9115ce707e7b10535f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Wed, 14 Jan 2026 12:30:59 +0100 Subject: [PATCH 4/8] Separate find_newline function --- src/java_symbols.hpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/java_symbols.hpp b/src/java_symbols.hpp index b344a44..8d47006 100644 --- a/src/java_symbols.hpp +++ b/src/java_symbols.hpp @@ -418,6 +418,25 @@ inline bool name_matches(std::string_view name, std::span pat return false; } +/*! + * Iterates over @p content to find newline starting from position @p pos. + * + * @return The position of the newline or `-1` if not found. + */ +inline std::ptrdiff_t find_newline(std::string_view content, std::ptrdiff_t pos) +{ + while (pos != std::ssize(content) and std::isspace(static_cast(content[pos]))) + { + if (content[pos] == '\n') + { + return pos; + } + ++pos; + } + + return -1; +} + /*! * Iterates over @p content to remove all import statements provided * as @p patterns and @p names. Patterns match the string representation @@ -472,20 +491,9 @@ inline std::tuple remove_imports( std::tie(symbol, end_pos) = next_symbol(content, end_pos); } - // Skip whitespace until one newline but only if a newline is found + if (auto skip_space = find_newline(content, end_pos); skip_space != -1) { - auto skip_space = end_pos; - - while (skip_space != std::ssize(content) and std::isspace(static_cast(content[skip_space]))) - { - ++skip_space; - - if (content[skip_space - 1] == '\n') - { - end_pos = skip_space; - break; - } - } + end_pos = skip_space + 1; } copy_end = end_pos; From c1134e722c47ef503028cf47107e9978f9923fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Wed, 14 Jan 2026 17:16:40 +0100 Subject: [PATCH 5/8] Implement module requires removal Fixes: https://github.com/fedora-java/jurand/issues/37 --- Makefile | 1 + README.adoc | 5 +- macros/macros.jurand | 8 + manpages/java_remove.7.adoc | 121 ++++++++++++++ manpages/jurand.1.adoc | 8 +- src/java_symbols.hpp | 147 ++++++++++++++++-- src/jurand.cpp | 18 ++- test.sh | 33 ++++ .../module_termination_1/module-info.java | 5 + .../module_termination_2/module-info.java | 5 + .../module_termination_3/module-info.java | 4 + .../module_termination_4/module-info.java | 4 + .../module_termination_5/module-info.java | 5 + .../module_termination_6/module-info.java | 5 + .../simple_module/module-info.1.java | 49 ++++++ .../simple_module/module-info.2.java | 53 +++++++ .../simple_module/module-info.3.java | 55 +++++++ .../simple_module/module-info.4.java | 53 +++++++ .../simple_module/module-info.5.java | 42 +++++ test_resources/simple_module/module-info.java | 56 +++++++ 20 files changed, 662 insertions(+), 15 deletions(-) create mode 100644 manpages/java_remove.7.adoc create mode 100644 test_resources/module_termination_1/module-info.java create mode 100644 test_resources/module_termination_2/module-info.java create mode 100644 test_resources/module_termination_3/module-info.java create mode 100644 test_resources/module_termination_4/module-info.java create mode 100644 test_resources/module_termination_5/module-info.java create mode 100644 test_resources/module_termination_6/module-info.java create mode 100644 test_resources/simple_module/module-info.1.java create mode 100644 test_resources/simple_module/module-info.2.java create mode 100644 test_resources/simple_module/module-info.3.java create mode 100644 test_resources/simple_module/module-info.4.java create mode 100644 test_resources/simple_module/module-info.5.java create mode 100644 test_resources/simple_module/module-info.java diff --git a/Makefile b/Makefile index c18bbcf..6af6e5e 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ $(call Executable_file,jurand_test): $(call Object_file,jurand_test.cpp) manpages: \ $(call Manpage,jurand.1)\ + $(call Manpage,java_remove.7)\ $(call Manpage,java_remove_annotations.7)\ $(call Manpage,java_remove_imports.7)\ diff --git a/README.adoc b/README.adoc index cf1b5cd..0e967c7 100644 --- a/README.adoc +++ b/README.adoc @@ -5,7 +5,7 @@ A tool for manipulating symbols present in `.java` source files. The tool can be used for patching `.java` sources in cases where using `sed` is insufficient due to Java language syntax. The tool follows Java language rules rather than applying simple regular expressions on the source code. -Currently the tool is able to remove `import` statements and annotations. +Currently the tool is able to remove `import` statements, annotations and modular `requires` statements. == Usage ---- @@ -16,6 +16,7 @@ Matcher:: [horizontal] `-n `::: Simple (not fully-qualified) class name. `-p `::: Regex pattern to match names used in code. +`-m `::: Regex pattern to match module name `requires` fields used in `module-info.java` files. [horizontal!] Optional flags:: @@ -36,10 +37,12 @@ File path arguments are handled the following way: * Symlinks are ignored * Regular files are handled regardless of the file name * Directories are traversed recursively and all `.java` files are handled +* Files named `module-info.java` are handled specifically If no file path is provided then the tool reads from the standard input. Class name matching can be done in two ways: `-n` to match simple class names or `-p` to match the provided regex pattern against fully qualified names as present in the sources. +Modular `requires` statements are matched using the `-m` flag provding a regex pattern. These options can be specified multiple times. The specific implementation of the regex search engine is subject to change. diff --git a/macros/macros.jurand b/macros/macros.jurand index 24c69e9..90cc23a 100644 --- a/macros/macros.jurand +++ b/macros/macros.jurand @@ -1,3 +1,11 @@ +# java_remove - remove dependency declarations or annotations from Java source files +# +# Usage: *%java_remove* [-n ]... [-p|-m ]... [file path]... +# +# Removes dependency declarations or annotations from Java source files by matching +# them against the lists of simple class names and patterns. +%java_remove %{_bindir}/jurand -i + # java_remove_imports - remove import statements from Java source files # # Usage: *%java_remove_imports* [-n ]... [-p ]... [file path]... diff --git a/manpages/java_remove.7.adoc b/manpages/java_remove.7.adoc new file mode 100644 index 0000000..2bbefee --- /dev/null +++ b/manpages/java_remove.7.adoc @@ -0,0 +1,121 @@ += java_remove(7) +:doctype: manpage +:mansource: JAVA_REMOVE +:manmanual: Java packaging support + +== NAME +java_remove - remove dependency declarations or annotations from Java source files + +== SYNOPSIS +*%java_remove* [optional flags] ... [file path]... + +== DESCRIPTION +This macro removes annotations, corresponding *import* statements and modular *requires* statements from Java source files. + +Annotations and import statements are matched using *-p* and *-n* flags. +Modular requires statements are matched using the *-m* flag. + +The tool matches all non-whitespace content following the 'import [static]' statement against all patterns provided via the *-p* flag and all simple class names against names provided by the *-n* flag. + +In *module-info.java* files, all content following 'requires [static] [transitive]' is matched against all patterns provided via the *-m* flag. + +File path arguments are handled the following way: + +* Symlinks are ignored. +* Regular files are handled regardless of the file name. +* Directories are traversed recursively and all `.java` files are handled. + +Arguments can be specified in arbitrary order. + +Optional flags: + +*-s*, *--strict*:: +Fail if any of the user provided arguments were redundant. + +*-a*:: +Also remove annotations used in code. +Annotations will be matched by the non-modular matchers. + +Matcher is one of: + +*-n *:: +Simple class name to be matched against the simple names of imported symbols. +Names are matched for exact equality. +Can be specified multiple times. + +*-p *:: +Regex patterns to be matched against imported symbols. +Each imported symbol found in the code is matched against each pattern. +Can be specified multiple times. + +*-m *:: +Regex pattern to match module name `requires` fields used in `module-info.java` files. +Can be specified multiple times. + +== EXAMPLES +Examples of usage in a *.spec* file: + +- *%java_remove module-api module-impl module-tests -s -a -n Nullable* +- *%java_remove src -s -a -p org[.]jspecify[.]annotations -m org[.]jspecify* + +=== Import patterns: +- Import statements present in Java source file: + + 1) import java.lang.Runnable; + 2) import java.util.List; + 3) import static java.util.*; + 4) import static java.lang.String.valueOf; + 5) import com.google.common.util.concurrent.Service; + +- Names used to match: + + Name 'Runnable' matches 1) + Name 'String' matches 4) + + Name 'util' does not match anything. + Name '*' does not match anything. + Name 'valueOf' does not match anything. + +- Patterns used to match: + + Pattern 'Runnable' matches 1). + Pattern '[*]' matches 3). + Pattern 'java[.]util' matches 2), 3). + Pattern 'util' matches 2), 3), 5). + Patterns 'java', 'java.*' match 1) - 4). + + Pattern 'static' does not match anything. + +=== Annotations +- Annotations present in Java source file: + + 1) @SuppressWarnings + 2) @SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"}) + 3) @org.junit.Test + 4) @org.junit.jupiter.api.Test + +- Names used to match: + + Name 'SuppressWarnings' matches 1) + Name 'Test' matches 3), 4). + + Name 'junit' does not match anything. + +- Patterns used to match: + + Pattern 'SuppressWarnings' matches 1). + Pattern 'Suppress' matches 1), 2). + Pattern 'org[.]junit[.]Test' matches 3). + Pattern 'junit' matches 3), 4). + + Pattern '@SuppressWarnings' does not match anything. + Pattern 'EI_EXPOSE_REP' does not match anything. + +== REPORTING BUGS +Bugs should be reported through the issue tracker at GitHub: https://github.com/fedora-java/jurand/issues. + +== AUTHOR +Written by Marián Konček. + +== SEE ALSO +*jurand*(1). diff --git a/manpages/jurand.1.adoc b/manpages/jurand.1.adoc index c35fdc9..8e1f070 100644 --- a/manpages/jurand.1.adoc +++ b/manpages/jurand.1.adoc @@ -7,7 +7,7 @@ jurand - Java removal of annotations == SYNOPSIS -*jurand* [*-a*] [*-i*] [*-s*] [*-n*=__] [*-p*=] [__...] +*jurand* [*-a*] [*-i*] [*-s*] [*-n*=__] [*-p|-m*=__] [__...] == DESCRIPTION A tool for manipulating symbols present in `.java` source files. @@ -15,7 +15,7 @@ A tool for manipulating symbols present in `.java` source files. The tool can be used for patching `.java` sources in cases where using sed is insufficient due to Java language syntax. The tool follows Java language rules rather than applying simple regular expressions on the source code. -Currently the tool is able to remove `import` statements and annotations. +Currently the tool is able to remove `import` statements, annotations and module `requires` statements. == OPTIONS *-n __:: @@ -24,6 +24,9 @@ Simple (not fully-qualified) class name. *-p __:: Regex pattern to match names used in code. +*-m __:: +Regex pattern to match module name `requires` fields used in `module-info.java` files. + *-a*:: Also remove annotations used in code. @@ -41,5 +44,6 @@ Bugs should be reported through the Jurand issue tracker at Github: https://gith Written by Marián Konček. == SEE ALSO +*java_remove*(7), *java_remove_annotations*(7), *java_remove_imports*(7). diff --git a/src/java_symbols.hpp b/src/java_symbols.hpp index 8d47006..68755dc 100644 --- a/src/java_symbols.hpp +++ b/src/java_symbols.hpp @@ -113,6 +113,7 @@ struct Mutex struct Parameters { std::vector patterns_; + std::vector module_patterns_; String_view_set names_; bool also_remove_annotations_ = false; bool in_place_ = false; @@ -123,6 +124,7 @@ struct Strict_mode { std::atomic any_annotation_removed_ = false; Mutex>> patterns_matched_; + Mutex>> module_patterns_matched_; Mutex>> names_matched_; Mutex> files_truncated_; }; @@ -587,24 +589,141 @@ inline std::string remove_annotations(std::string_view content, std::span module_patterns) +{ + auto new_content = std::string(content); + new_content.reserve(content.size()); + + auto pos = std::ptrdiff_t(0); + pos = find_token(content, "module"); + pos = find_token(content, "{", pos); + + if (pos != std::ssize(content)) + { + ++pos; + new_content.clear(); + new_content.append(content, 0, pos); + while (pos != std::ssize(content)) + { + auto symbol = std::string_view(); + auto end_pos = std::ptrdiff_t(0); + auto old_pos = pos; + std::tie(symbol, end_pos) = next_symbol(content, pos); + + if (symbol.empty()) + { + break; + } + + if (symbol == "requires") + { + pos = end_pos; + } + else + { + pos = find_token(content, ";", pos); + if (pos != std::ssize(content)) + { + ++pos; + } + new_content.append(content, old_pos, pos - old_pos); + continue; + } + + std::tie(symbol, end_pos) = next_symbol(content, pos); + if (symbol == "transitive") + { + pos = end_pos; + } + else if (symbol == "static") + { + pos = end_pos; + std::tie(symbol, end_pos) = next_symbol(content, pos); + if (symbol == "transitive") + { + pos = end_pos; + } + } + + auto module_name = std::string(); + + std::tie(symbol, end_pos) = next_symbol(content, pos); + while (symbol != ";") + { + if (symbol.empty()) + { + new_content.clear(); + new_content.append(content); + return new_content; + } + + module_name += symbol; + std::tie(symbol, end_pos) = next_symbol(content, end_pos); + } + + pos = end_pos; + + bool matched = false; + for (const auto& pattern : module_patterns) + { + if (std::regex_search(module_name.begin(), module_name.end(), pattern)) + { + if (strict_mode) + { + strict_mode->module_patterns_matched_.lock().get().at(pattern) = true; + } + + matched = true; + break; + } + } + + if (matched) + { + if (auto skip_space = find_newline(content, pos); skip_space != -1) + { + pos = skip_space; + } + } + else + { + new_content.append(content, old_pos, pos - old_pos); + } + } + } + + return new_content; +} + //////////////////////////////////////////////////////////////////////////////// -inline std::string handle_content(std::string_view content, const Parameters& parameters) +inline std::string handle_content(const Path_origin_entry& path, std::string_view content, const Parameters& parameters) { - auto [new_content, removed_classes] = remove_imports(content, parameters.patterns_, parameters.names_); + auto result = std::string(); - if (parameters.also_remove_annotations_) + if (path.filename() == "module-info.java") + { + result = remove_jpms_requires(content, parameters.module_patterns_); + } + else { - auto content_size = new_content.size(); - new_content = remove_annotations(new_content, parameters.patterns_, parameters.names_, removed_classes); + auto [new_content, removed_classes] = remove_imports(content, parameters.patterns_, parameters.names_); - if (strict_mode and new_content.size() < content_size) + if (parameters.also_remove_annotations_) { - strict_mode->any_annotation_removed_.store(true, std::memory_order_release); + auto content_size = new_content.size(); + new_content = remove_annotations(new_content, parameters.patterns_, parameters.names_, removed_classes); + + if (strict_mode and new_content.size() < content_size) + { + strict_mode->any_annotation_removed_.store(true, std::memory_order_release); + } } + + result = new_content; } - return new_content; + return result; } inline std::string handle_file(const Path_origin_entry& path, const Parameters& parameters) @@ -629,7 +748,7 @@ try original_content = std::string(std::istreambuf_iterator(ifs), {}); } - auto content = handle_content(original_content, parameters); + auto content = handle_content(path, original_content, parameters); if (not parameters.in_place_) { @@ -714,14 +833,20 @@ inline Parameters interpret_args(const Parameter_dict& parameters) if (auto it = parameters.find("-p"); it != parameters.end()) { - result.patterns_.reserve(it->second.size()); - for (const auto& pattern : it->second) { result.patterns_.emplace_back(pattern, std::regex_constants::extended); } } + if (auto it = parameters.find("-m"); it != parameters.end()) + { + for (const auto& pattern : it->second) + { + result.module_patterns_.emplace_back(pattern, std::regex_constants::extended); + } + } + if (auto it = parameters.find("-n"); it != parameters.end()) { for (const auto& name : it->second) diff --git a/src/jurand.cpp b/src/jurand.cpp index 280f677..771645a 100644 --- a/src/jurand.cpp +++ b/src/jurand.cpp @@ -21,6 +21,8 @@ Usage: jurand [optional flags] ... [file path]... simple (not fully-qualified) class name -p regex pattern to match names used in code + -m + regex pattern to match module name requires fields used in 'module-info.java' files Optional flags: -a also remove annotations used in code @@ -38,7 +40,7 @@ Usage: jurand [optional flags] ... [file path]... const auto parameters = interpret_args(parameter_dict); - if (parameters.names_.empty() and parameters.patterns_.empty()) + if (parameters.names_.empty() and parameters.patterns_.empty() and parameters.module_patterns_.empty()) { std::cout << "jurand: no matcher specified" << "\n"; return 1; @@ -113,6 +115,11 @@ Usage: jurand [optional flags] ... [file path]... strict_mode->patterns_matched_.lock().get().try_emplace(pattern); } + for (const auto& pattern : parameters.module_patterns_) + { + strict_mode->module_patterns_matched_.lock().get().try_emplace(pattern); + } + for (const auto& name : parameters.names_) { strict_mode->names_matched_.lock().get().try_emplace(name); @@ -196,6 +203,15 @@ Usage: jurand [optional flags] ... [file path]... } } + for (const auto& pattern_entry : strict_mode->module_patterns_matched_.lock().get()) + { + if (not pattern_entry.second) + { + std::cout << "jurand: strict mode: module pattern " << pattern_entry.first << " did not match anything" << "\n"; + exit_code = 3; + } + } + if (parameters.also_remove_annotations_ and not strict_mode->any_annotation_removed_.load(std::memory_order_acquire)) { std::cout << "jurand: strict mode: '-a' was specified but no annotation was removed" << "\n"; diff --git a/test.sh b/test.sh index 93557cd..6731cd3 100755 --- a/test.sh +++ b/test.sh @@ -11,6 +11,9 @@ mkdir -p target/test_resources run_tool() { local filename="${1}"; shift + if [[ "${filename}" == */* ]]; then + mkdir -p "target/test_resources/${filename%/*}" + fi cp -r "test_resources/${filename}" "target/test_resources/${filename}" ./target/bin/jurand -i "target/test_resources/${filename}" "${@}" } @@ -19,6 +22,9 @@ test_file() { local filename="${1}"; shift local expected="${1}"; shift + if [ -d "test_resources/${expected%/*}" ]; then + mkdir -p "target/test_resources/${expected%/*}" + fi cp "test_resources/${expected}" "target/test_resources/${expected}" run_tool "${filename}" "${@}" diff -u "target/test_resources/${filename}" "target/test_resources/${expected}" @@ -152,6 +158,27 @@ test_file "Array.java" "Array.5.java" -a -n C -n D -n E -n F test_file "Package_info.java" "Package_info.1.java" -a -n MyAnn +################################################################################ +# Tests for module-info handling +test_file "simple_module/module-info.java" "simple_module/module-info.1.java" -m "java[.]base" +# Remove requires transitive +test_file "simple_module/module-info.java" "simple_module/module-info.2.java" -m "java[.]sql" +# Remove requires static +test_file "simple_module/module-info.java" "simple_module/module-info.3.java" -m "java[.]logging" +# Remove requires static transitive +test_file "simple_module/module-info.java" "simple_module/module-info.4.java" -m "org[.]jetbrains" +# Remove all requires +test_file "simple_module/module-info.java" "simple_module/module-info.5.java" -m "java" -m "org[.]jetbrains" + +################################################################################ +# Tests for tool termination on invalid module-info.java sources +run_tool "module_termination_1/module-info.java" -m "java" || : +run_tool "module_termination_2/module-info.java" -m "java" || : +run_tool "module_termination_3/module-info.java" -m "java" || : +run_tool "module_termination_4/module-info.java" -m "java" || : +run_tool "module_termination_5/module-info.java" -m "java" || : +run_tool "module_termination_6/module-info.java" -m "java" || : + ################################################################################ # Tests for tool termination on invalid sources, result is irrelevant @@ -189,6 +216,12 @@ test_strict "Strict.2.java" "Strict.2.java" -a -n "C" # Should print the directory name run_tool "directory" -a -s -n "XXX" | grep "strict mode:.*/directory" 1>/dev/null +# Strict mode tests for module patterns +# Successful for coverage +test_file "simple_module/module-info.java" "simple_module/module-info.1.java" -s -m "java[.]base" +# Module pattern that doesn't match anything +test_strict "simple_module/module-info.java" "simple_module/module-info.java" -m "nonexistent[.]module" + ################################################################################ echo "[PASS] Integration tests" diff --git a/test_resources/module_termination_1/module-info.java b/test_resources/module_termination_1/module-info.java new file mode 100644 index 0000000..84a7575 --- /dev/null +++ b/test_resources/module_termination_1/module-info.java @@ -0,0 +1,5 @@ +// Missing semicolon after requires +module com.example.module { + requires java.base +} + diff --git a/test_resources/module_termination_2/module-info.java b/test_resources/module_termination_2/module-info.java new file mode 100644 index 0000000..22baed0 --- /dev/null +++ b/test_resources/module_termination_2/module-info.java @@ -0,0 +1,5 @@ +// Missing module name after requires +module com.example.module { + requires ; +} + diff --git a/test_resources/module_termination_3/module-info.java b/test_resources/module_termination_3/module-info.java new file mode 100644 index 0000000..2c64e9b --- /dev/null +++ b/test_resources/module_termination_3/module-info.java @@ -0,0 +1,4 @@ +// Incomplete requires statement - EOF after requires +module com.example.module { + requires + diff --git a/test_resources/module_termination_4/module-info.java b/test_resources/module_termination_4/module-info.java new file mode 100644 index 0000000..bfeb496 --- /dev/null +++ b/test_resources/module_termination_4/module-info.java @@ -0,0 +1,4 @@ +// Missing closing brace +module com.example.module { + requires java.base; + diff --git a/test_resources/module_termination_5/module-info.java b/test_resources/module_termination_5/module-info.java new file mode 100644 index 0000000..a271daa --- /dev/null +++ b/test_resources/module_termination_5/module-info.java @@ -0,0 +1,5 @@ +// Module without opening brace +module com.example.module + requires java.base; +} + diff --git a/test_resources/module_termination_6/module-info.java b/test_resources/module_termination_6/module-info.java new file mode 100644 index 0000000..eae2b50 --- /dev/null +++ b/test_resources/module_termination_6/module-info.java @@ -0,0 +1,5 @@ +// Incomplete requires with static modifier +module com.example.module { + requires static +} + diff --git a/test_resources/simple_module/module-info.1.java b/test_resources/simple_module/module-info.1.java new file mode 100644 index 0000000..76f1bfb --- /dev/null +++ b/test_resources/simple_module/module-info.1.java @@ -0,0 +1,49 @@ +/** + * Sample module-info.java demonstrating all JPMS constructs + */ +@Deprecated +module com.example.full.module { + + // Requires with modifiers + requires transitive java.sql; + requires static java.logging; + + // Combined modifiers + requires static transitive org.jetbrains.annotations; + + /* + * ---- EXPORTS ---- + */ + + // Unqualified export + exports com.example.api; + + // Qualified export + exports com.example.internal + to com.example.friend, + com.example.another.friend; + + /* + * ---- OPENS ---- + */ + + // Unqualified open + opens com.example.model; + + // Qualified open + opens com.example.secret + to com.fasterxml.jackson.databind, + com.google.gson; + + /* + * ---- SERVICES ---- + */ + + // Service usage + uses com.example.spi.Plugin; + + // Service provision + provides com.example.spi.Plugin + with com.example.impl.PluginImpl, + com.example.impl.AnotherPluginImpl; +} diff --git a/test_resources/simple_module/module-info.2.java b/test_resources/simple_module/module-info.2.java new file mode 100644 index 0000000..2562a62 --- /dev/null +++ b/test_resources/simple_module/module-info.2.java @@ -0,0 +1,53 @@ +/** + * Sample module-info.java demonstrating all JPMS constructs + */ +@Deprecated +module com.example.full.module { + + /* + * ---- REQUIRES ---- + */ + + // Simple requires + requires java.base; + requires static java.logging; + + // Combined modifiers + requires static transitive org.jetbrains.annotations; + + /* + * ---- EXPORTS ---- + */ + + // Unqualified export + exports com.example.api; + + // Qualified export + exports com.example.internal + to com.example.friend, + com.example.another.friend; + + /* + * ---- OPENS ---- + */ + + // Unqualified open + opens com.example.model; + + // Qualified open + opens com.example.secret + to com.fasterxml.jackson.databind, + com.google.gson; + + /* + * ---- SERVICES ---- + */ + + // Service usage + uses com.example.spi.Plugin; + + // Service provision + provides com.example.spi.Plugin + with com.example.impl.PluginImpl, + com.example.impl.AnotherPluginImpl; +} diff --git a/test_resources/simple_module/module-info.3.java b/test_resources/simple_module/module-info.3.java new file mode 100644 index 0000000..224d6f9 --- /dev/null +++ b/test_resources/simple_module/module-info.3.java @@ -0,0 +1,55 @@ +/** + * Sample module-info.java demonstrating all JPMS constructs + */ +@Deprecated +module com.example.full.module { + + /* + * ---- REQUIRES ---- + */ + + // Simple requires + requires java.base; + + // Requires with modifiers + requires transitive java.sql; + + // Combined modifiers + requires static transitive org.jetbrains.annotations; + + /* + * ---- EXPORTS ---- + */ + + // Unqualified export + exports com.example.api; + + // Qualified export + exports com.example.internal + to com.example.friend, + com.example.another.friend; + + /* + * ---- OPENS ---- + */ + + // Unqualified open + opens com.example.model; + + // Qualified open + opens com.example.secret + to com.fasterxml.jackson.databind, + com.google.gson; + + /* + * ---- SERVICES ---- + */ + + // Service usage + uses com.example.spi.Plugin; + + // Service provision + provides com.example.spi.Plugin + with com.example.impl.PluginImpl, + com.example.impl.AnotherPluginImpl; +} diff --git a/test_resources/simple_module/module-info.4.java b/test_resources/simple_module/module-info.4.java new file mode 100644 index 0000000..773ee5b --- /dev/null +++ b/test_resources/simple_module/module-info.4.java @@ -0,0 +1,53 @@ +/** + * Sample module-info.java demonstrating all JPMS constructs + */ +@Deprecated +module com.example.full.module { + + /* + * ---- REQUIRES ---- + */ + + // Simple requires + requires java.base; + + // Requires with modifiers + requires transitive java.sql; + requires static java.logging; + + /* + * ---- EXPORTS ---- + */ + + // Unqualified export + exports com.example.api; + + // Qualified export + exports com.example.internal + to com.example.friend, + com.example.another.friend; + + /* + * ---- OPENS ---- + */ + + // Unqualified open + opens com.example.model; + + // Qualified open + opens com.example.secret + to com.fasterxml.jackson.databind, + com.google.gson; + + /* + * ---- SERVICES ---- + */ + + // Service usage + uses com.example.spi.Plugin; + + // Service provision + provides com.example.spi.Plugin + with com.example.impl.PluginImpl, + com.example.impl.AnotherPluginImpl; +} diff --git a/test_resources/simple_module/module-info.5.java b/test_resources/simple_module/module-info.5.java new file mode 100644 index 0000000..468a1b0 --- /dev/null +++ b/test_resources/simple_module/module-info.5.java @@ -0,0 +1,42 @@ +/** + * Sample module-info.java demonstrating all JPMS constructs + */ +@Deprecated +module com.example.full.module { + + /* + * ---- EXPORTS ---- + */ + + // Unqualified export + exports com.example.api; + + // Qualified export + exports com.example.internal + to com.example.friend, + com.example.another.friend; + + /* + * ---- OPENS ---- + */ + + // Unqualified open + opens com.example.model; + + // Qualified open + opens com.example.secret + to com.fasterxml.jackson.databind, + com.google.gson; + + /* + * ---- SERVICES ---- + */ + + // Service usage + uses com.example.spi.Plugin; + + // Service provision + provides com.example.spi.Plugin + with com.example.impl.PluginImpl, + com.example.impl.AnotherPluginImpl; +} diff --git a/test_resources/simple_module/module-info.java b/test_resources/simple_module/module-info.java new file mode 100644 index 0000000..4650335 --- /dev/null +++ b/test_resources/simple_module/module-info.java @@ -0,0 +1,56 @@ +/** + * Sample module-info.java demonstrating all JPMS constructs + */ +@Deprecated +module com.example.full.module { + + /* + * ---- REQUIRES ---- + */ + + // Simple requires + requires java.base; + + // Requires with modifiers + requires transitive java.sql; + requires static java.logging; + + // Combined modifiers + requires static transitive org.jetbrains.annotations; + + /* + * ---- EXPORTS ---- + */ + + // Unqualified export + exports com.example.api; + + // Qualified export + exports com.example.internal + to com.example.friend, + com.example.another.friend; + + /* + * ---- OPENS ---- + */ + + // Unqualified open + opens com.example.model; + + // Qualified open + opens com.example.secret + to com.fasterxml.jackson.databind, + com.google.gson; + + /* + * ---- SERVICES ---- + */ + + // Service usage + uses com.example.spi.Plugin; + + // Service provision + provides com.example.spi.Plugin + with com.example.impl.PluginImpl, + com.example.impl.AnotherPluginImpl; +} From 4c6ad08726d848b18abf3ade038614d08201330c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Mon, 2 Feb 2026 14:27:00 +0100 Subject: [PATCH 6/8] Remove %java_remove* RPM macros --- Makefile | 4 - install.sh | 1 - macros/macros.jurand | 25 ----- manpages/java_remove.7.adoc | 121 ------------------------ manpages/java_remove_annotations.7.adoc | 81 ---------------- manpages/java_remove_imports.7.adoc | 82 ---------------- manpages/jurand.1.adoc | 87 ++++++++++++++--- 7 files changed, 76 insertions(+), 325 deletions(-) delete mode 100644 macros/macros.jurand delete mode 100644 manpages/java_remove.7.adoc delete mode 100644 manpages/java_remove_annotations.7.adoc delete mode 100644 manpages/java_remove_imports.7.adoc diff --git a/Makefile b/Makefile index 6af6e5e..1c86328 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,9 @@ $(call Executable_file,jurand_test): $(call Object_file,jurand_test.cpp) manpages: \ $(call Manpage,jurand.1)\ - $(call Manpage,java_remove.7)\ - $(call Manpage,java_remove_annotations.7)\ - $(call Manpage,java_remove_imports.7)\ test-install: export buildroot = target/buildroot test-install: export bindir = /usr/bin -test-install: export rpmmacrodir = /usr/lib/rpm/macros.d test-install: export mandir = /usr/share/man test-install: all manpages ./install.sh diff --git a/install.sh b/install.sh index 7395aab..eccaf93 100755 --- a/install.sh +++ b/install.sh @@ -25,5 +25,4 @@ install_file() } install_file 755 "${bindir}" target/bin/jurand -install_file 644 "${rpmmacrodir}" macros/macros.jurand install_file 644 "${mandir}" target/manpages/* diff --git a/macros/macros.jurand b/macros/macros.jurand deleted file mode 100644 index 90cc23a..0000000 --- a/macros/macros.jurand +++ /dev/null @@ -1,25 +0,0 @@ -# java_remove - remove dependency declarations or annotations from Java source files -# -# Usage: *%java_remove* [-n ]... [-p|-m ]... [file path]... -# -# Removes dependency declarations or annotations from Java source files by matching -# them against the lists of simple class names and patterns. -%java_remove %{_bindir}/jurand -i - -# java_remove_imports - remove import statements from Java source files -# -# Usage: *%java_remove_imports* [-n ]... [-p ]... [file path]... -# -# Removes import statements from Java source files by matching them against the -# lists of simple class names and patterns. -%java_remove_imports %{_bindir}/jurand -i - - -# java_remove_annotations - remove imports and annotations from Java source -# files -# -# Usage: *%java_remove_annotations* [-n ]... [-p ]... [file path]... -# -# Removes import statements as well as usage of annotations from Java source -# files by matching them against the lists of simple class names and patterns. -%java_remove_annotations %{_bindir}/jurand -i -a diff --git a/manpages/java_remove.7.adoc b/manpages/java_remove.7.adoc deleted file mode 100644 index 2bbefee..0000000 --- a/manpages/java_remove.7.adoc +++ /dev/null @@ -1,121 +0,0 @@ -= java_remove(7) -:doctype: manpage -:mansource: JAVA_REMOVE -:manmanual: Java packaging support - -== NAME -java_remove - remove dependency declarations or annotations from Java source files - -== SYNOPSIS -*%java_remove* [optional flags] ... [file path]... - -== DESCRIPTION -This macro removes annotations, corresponding *import* statements and modular *requires* statements from Java source files. - -Annotations and import statements are matched using *-p* and *-n* flags. -Modular requires statements are matched using the *-m* flag. - -The tool matches all non-whitespace content following the 'import [static]' statement against all patterns provided via the *-p* flag and all simple class names against names provided by the *-n* flag. - -In *module-info.java* files, all content following 'requires [static] [transitive]' is matched against all patterns provided via the *-m* flag. - -File path arguments are handled the following way: - -* Symlinks are ignored. -* Regular files are handled regardless of the file name. -* Directories are traversed recursively and all `.java` files are handled. - -Arguments can be specified in arbitrary order. - -Optional flags: - -*-s*, *--strict*:: -Fail if any of the user provided arguments were redundant. - -*-a*:: -Also remove annotations used in code. -Annotations will be matched by the non-modular matchers. - -Matcher is one of: - -*-n *:: -Simple class name to be matched against the simple names of imported symbols. -Names are matched for exact equality. -Can be specified multiple times. - -*-p *:: -Regex patterns to be matched against imported symbols. -Each imported symbol found in the code is matched against each pattern. -Can be specified multiple times. - -*-m *:: -Regex pattern to match module name `requires` fields used in `module-info.java` files. -Can be specified multiple times. - -== EXAMPLES -Examples of usage in a *.spec* file: - -- *%java_remove module-api module-impl module-tests -s -a -n Nullable* -- *%java_remove src -s -a -p org[.]jspecify[.]annotations -m org[.]jspecify* - -=== Import patterns: -- Import statements present in Java source file: - - 1) import java.lang.Runnable; - 2) import java.util.List; - 3) import static java.util.*; - 4) import static java.lang.String.valueOf; - 5) import com.google.common.util.concurrent.Service; - -- Names used to match: - - Name 'Runnable' matches 1) - Name 'String' matches 4) - - Name 'util' does not match anything. - Name '*' does not match anything. - Name 'valueOf' does not match anything. - -- Patterns used to match: - - Pattern 'Runnable' matches 1). - Pattern '[*]' matches 3). - Pattern 'java[.]util' matches 2), 3). - Pattern 'util' matches 2), 3), 5). - Patterns 'java', 'java.*' match 1) - 4). - - Pattern 'static' does not match anything. - -=== Annotations -- Annotations present in Java source file: - - 1) @SuppressWarnings - 2) @SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"}) - 3) @org.junit.Test - 4) @org.junit.jupiter.api.Test - -- Names used to match: - - Name 'SuppressWarnings' matches 1) - Name 'Test' matches 3), 4). - - Name 'junit' does not match anything. - -- Patterns used to match: - - Pattern 'SuppressWarnings' matches 1). - Pattern 'Suppress' matches 1), 2). - Pattern 'org[.]junit[.]Test' matches 3). - Pattern 'junit' matches 3), 4). - - Pattern '@SuppressWarnings' does not match anything. - Pattern 'EI_EXPOSE_REP' does not match anything. - -== REPORTING BUGS -Bugs should be reported through the issue tracker at GitHub: https://github.com/fedora-java/jurand/issues. - -== AUTHOR -Written by Marián Konček. - -== SEE ALSO -*jurand*(1). diff --git a/manpages/java_remove_annotations.7.adoc b/manpages/java_remove_annotations.7.adoc deleted file mode 100644 index 67ba131..0000000 --- a/manpages/java_remove_annotations.7.adoc +++ /dev/null @@ -1,81 +0,0 @@ -= java_remove_annotations(7) -:doctype: manpage -:mansource: JAVA_REMOVE_ANNOTATIONS -:manmanual: Java packaging support - -== NAME -java_remove_annotations - remove imports and annotations from Java source files - -== SYNOPSIS -*%java_remove_annotations* [optional flags] ... [file path]... - -== DESCRIPTION -This macro removes import statements as well as usage of annotations from Java source files. -This does the same as *java_remove_imports* and on top of that finds all uses of annotations and matches the content between the '@' symbol and either ending with whitespace or with an opening parethesis '(' (the annotation arguments). - -In case of match, the script also removes the block of paretheses that follows the matched annotation, if it is present. - -File path arguments are handled the following way: - -* Symlinks are ignored. -* Regular files are handled regardless of the file name. -* Directories are traversed recursively and all `.java` files are handled. - -Arguments can be specified in arbitrary order. - -Matcher is one of: - -*-n *:: -Simple class name to be matched against the simple names of imported symbols. -Names are matched for exact equality. -Can be specified multiple times. - -*-p *:: -Regex patterns to be matched against imported symbols. -Each imported symbol found in the code is matched against each pattern. -Can be specified multiple times. - -Optional flags: - -*-s, --strict*:: -Fail if any of the user provided arguments were redundant. - -== EXAMPLES -Example of usage in a *.spec* file: - -*%java_remove_annotations src -n Nullable* - -Examples of patterns: - -- Annotations present in Java source file: - - 1) @SuppressWarnings - 2) @SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"}) - 3) @org.junit.Test - 4) @org.junit.jupiter.api.Test - -- Names used to match: - - Name 'SuppressWarnings' matches 1) - Name 'Test' matches 3), 4). - - Name 'junit' does not match anything. - -- Patterns used to match: - - Pattern 'SuppressWarnings' matches 1). - Pattern 'Suppress' matches 1), 2). - Pattern 'org[.]junit[.]Test' matches 3). - Pattern 'junit' matches 3), 4). - - Pattern '@SuppressWarnings' does not match anything. - Pattern 'EI_EXPOSE_REP' does not match anything. - -== REPORTING BUGS -Bugs should be reported through the issue tracker at GitHub: https://github.com/fedora-java/jurand/issues. - -== AUTHOR -Written by Marián Konček. - -== SEE ALSO -*java_remove_imports*(7). diff --git a/manpages/java_remove_imports.7.adoc b/manpages/java_remove_imports.7.adoc deleted file mode 100644 index 53e4069..0000000 --- a/manpages/java_remove_imports.7.adoc +++ /dev/null @@ -1,82 +0,0 @@ -= java_remove_imports(7) -:doctype: manpage -:mansource: JAVA_REMOVE_IMPORTS -:manmanual: Java packaging support - -== NAME -java_remove_imports - remove import statements from Java source files - -== SYNOPSIS -*%java_remove_imports* [optional flags] ... [file path]... - -== DESCRIPTION -This macro removes import statements from Java source files. -The script matches all non-whitespace content following the 'import [static]' statement against all patterns provided via the *-p* flag and all simple class names against names provided by the *-n* flag. - -File path arguments are handled the following way: - -* Symlinks are ignored. -* Regular files are handled regardless of the file name. -* Directories are traversed recursively and all `.java` files are handled. - -Arguments can be specified in arbitrary order. - -Matcher is one of: - -*-n *:: -Simple class name to be matched against the simple names of imported symbols. -Names are matched for exact equality. -Can be specified multiple times. - -*-p *:: -Regex patterns to be matched against imported symbols. -Each imported symbol found in the code is matched against each pattern. -Can be specified multiple times. - -Optional flags: - -*-s, --strict*:: -Fail if any of the user provided arguments were redundant. - -== EXAMPLES -Example of usage in a *.spec* file: - -*%java_remove_imports src -n Nullable* - -Examples of patterns: - -- Import statements present in Java source file: - - 1) import java.lang.Runnable; - 2) import java.util.List; - 3) import static java.util.*; - 4) import static java.lang.String.valueOf; - 5) import com.google.common.util.concurrent.Service; - -- Names used to match: - - Name 'Runnable' matches 1) - Name 'String' matches 4) - - Name 'util' does not match anything. - Name '*' does not match anything. - Name 'valueOf' does not match anything. - -- Patterns used to match: - - Pattern 'Runnable' matches 1). - Pattern '[*]' matches 3). - Pattern 'java[.]util' matches 2), 3). - Pattern 'util' matches 2), 3), 5). - Patterns 'java', 'java.*' match 1) - 4). - - Pattern 'static' does not match anything. - -== REPORTING BUGS -Bugs should be reported through the issue tracker at GitHub: https://github.com/fedora-java/jurand/issues. - -== AUTHOR -Written by Marián Konček. - -== SEE ALSO -*java_remove_annotations*(7). diff --git a/manpages/jurand.1.adoc b/manpages/jurand.1.adoc index 8e1f070..715b844 100644 --- a/manpages/jurand.1.adoc +++ b/manpages/jurand.1.adoc @@ -4,18 +4,29 @@ :manmanual: Jurand Manual == NAME -jurand - Java removal of annotations +jurand - remove dependency declarations or annotations from Java source files == SYNOPSIS -*jurand* [*-a*] [*-i*] [*-s*] [*-n*=__] [*-p|-m*=__] [__...] +*jurand* [*-i*] [*-s*] [*-a*] [*-n* __] [*-p|-m* __] [__...] == DESCRIPTION -A tool for manipulating symbols present in `.java` source files. +This tool removes annotations, corresponding *import* statements and modular *requires* statements from Java source files. -The tool can be used for patching `.java` sources in cases where using sed is insufficient due to Java language syntax. +The tool can be used for patching Java sources in cases where using sed is insufficient due to Java language syntax. The tool follows Java language rules rather than applying simple regular expressions on the source code. -Currently the tool is able to remove `import` statements, annotations and module `requires` statements. +The tool matches all non-whitespace content following the 'import [static]' statement against all patterns provided via the *-p* flag and all simple class names against names provided by the *-n* flag. + +In *module-info.java* files, all content following 'requires [static] [transitive]' is matched against all patterns provided via the *-m* flag. + +File path arguments are handled the following way: + +* Symlinks are ignored. +* Regular files are handled regardless of the file name. +* Directories are traversed recursively and all *.java* files are handled. +* *module-info.java* files are handled specifically. + +Arguments can be specified in arbitrary order. == OPTIONS *-n __:: @@ -25,7 +36,7 @@ Simple (not fully-qualified) class name. Regex pattern to match names used in code. *-m __:: -Regex pattern to match module name `requires` fields used in `module-info.java` files. +Regex pattern to match module name *requires* fields used in *module-info.java* files. *-a*:: Also remove annotations used in code. @@ -37,13 +48,67 @@ Replace the contents of files. Fail if any of the specified options was redundant and no changes associated with the option were made. This option is only applicable together with *-i*. +== EXAMPLES +Examples of usage in a *.spec* file: + +- *jurand -i -s -a module-api module-impl module-tests -n Nullable* +- *jurand -i -s -a src -p org[.]jspecify[.]annotations -m org[.]jspecify* + +=== Import patterns: +- Import statements present in Java source file: + + 1) import java.lang.Runnable; + 2) import java.util.List; + 3) import static java.util.*; + 4) import static java.lang.String.valueOf; + 5) import com.google.common.util.concurrent.Service; + +- Names used to match: + + Name 'Runnable' matches 1) + Name 'String' matches 4) + + Name 'util' does not match anything. + Name '*' does not match anything. + Name 'valueOf' does not match anything. + +- Patterns used to match: + + Pattern 'Runnable' matches 1). + Pattern '[*]' matches 3). + Pattern 'java[.]util' matches 2), 3). + Pattern 'util' matches 2), 3), 5). + Patterns 'java', 'java.*' match 1) - 4). + + Pattern 'static' does not match anything. + +=== Annotations +- Annotations present in Java source file: + + 1) @SuppressWarnings + 2) @SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"}) + 3) @org.junit.Test + 4) @org.junit.jupiter.api.Test + +- Names used to match: + + Name 'SuppressWarnings' matches 1) + Name 'Test' matches 3), 4). + + Name 'junit' does not match anything. + +- Patterns used to match: + + Pattern 'SuppressWarnings' matches 1). + Pattern 'Suppress' matches 1), 2). + Pattern 'org[.]junit[.]Test' matches 3). + Pattern 'junit' matches 3), 4). + + Pattern '@SuppressWarnings' does not match anything. + Pattern 'EI_EXPOSE_REP' does not match anything. + == REPORTING BUGS Bugs should be reported through the Jurand issue tracker at Github: https://github.com/fedora-java/jurand/issues. == AUTHOR Written by Marián Konček. - -== SEE ALSO -*java_remove*(7), -*java_remove_annotations*(7), -*java_remove_imports*(7). From 744ef8ea19a49d5075c79bc9d5141864df08f69f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Mon, 2 Feb 2026 14:34:51 +0100 Subject: [PATCH 7/8] Reword README --- README.adoc | 4 ++-- manpages/jurand.1.adoc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.adoc b/README.adoc index 0e967c7..996b3b8 100644 --- a/README.adoc +++ b/README.adoc @@ -1,8 +1,8 @@ = Jurand -- Java removal of annotations -A tool for manipulating symbols present in `.java` source files. +A tool for manipulating symbols present in Java source files. -The tool can be used for patching `.java` sources in cases where using `sed` is insufficient due to Java language syntax. +The tool can be used for patching Java sources in cases where using `sed` is insufficient due to Java language syntax. The tool follows Java language rules rather than applying simple regular expressions on the source code. Currently the tool is able to remove `import` statements, annotations and modular `requires` statements. diff --git a/manpages/jurand.1.adoc b/manpages/jurand.1.adoc index 715b844..f171b9c 100644 --- a/manpages/jurand.1.adoc +++ b/manpages/jurand.1.adoc @@ -13,7 +13,7 @@ jurand - remove dependency declarations or annotations from Java source files This tool removes annotations, corresponding *import* statements and modular *requires* statements from Java source files. The tool can be used for patching Java sources in cases where using sed is insufficient due to Java language syntax. -The tool follows Java language rules rather than applying simple regular expressions on the source code. +It follows Java language rules rather than applying simple regular expressions on the source code. The tool matches all non-whitespace content following the 'import [static]' statement against all patterns provided via the *-p* flag and all simple class names against names provided by the *-n* flag. @@ -24,7 +24,7 @@ File path arguments are handled the following way: * Symlinks are ignored. * Regular files are handled regardless of the file name. * Directories are traversed recursively and all *.java* files are handled. -* *module-info.java* files are handled specifically. +* Files named *module-info.java* are handled specifically. Arguments can be specified in arbitrary order. From cdfd8c1cfd7a8a21c05c02e9dbada3cff48f90ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mari=C3=A1n=20Kon=C4=8Dek?= Date: Mon, 2 Feb 2026 14:49:04 +0100 Subject: [PATCH 8/8] Drop unnecessary string copy --- src/java_symbols.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/java_symbols.hpp b/src/java_symbols.hpp index 68755dc..8f4f6d3 100644 --- a/src/java_symbols.hpp +++ b/src/java_symbols.hpp @@ -699,11 +699,9 @@ inline std::string remove_jpms_requires(std::string_view content, std::span