diff --git a/Makefile b/Makefile index c18bbcf..1c86328 100644 --- a/Makefile +++ b/Makefile @@ -17,12 +17,9 @@ $(call Executable_file,jurand_test): $(call Object_file,jurand_test.cpp) manpages: \ $(call Manpage,jurand.1)\ - $(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/README.adoc b/README.adoc index cf1b5cd..996b3b8 100644 --- a/README.adoc +++ b/README.adoc @@ -1,11 +1,11 @@ = 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 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/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 24c69e9..0000000 --- a/macros/macros.jurand +++ /dev/null @@ -1,17 +0,0 @@ -# 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_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 d447352..f171b9c 100644 --- a/manpages/jurand.1.adoc +++ b/manpages/jurand.1.adoc @@ -4,26 +4,40 @@ :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*=] [__...] +*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 follows Java language rules rather than applying simple regular expressions on the source code. +The tool can be used for patching Java sources in cases where using sed is insufficient due to Java language syntax. +It 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. +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. +* Files named *module-info.java* are handled specifically. + +Arguments can be specified in arbitrary order. == OPTIONS -*-n*, *--name*=__:: +*-n __:: Simple (not fully-qualified) class name. -*-p*, *--pattern*=__:: +*-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. @@ -34,12 +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_annotations*(7), -*java_remove_imports*(7). diff --git a/src/java_symbols.hpp b/src/java_symbols.hpp index b344a44..8f4f6d3 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_; }; @@ -418,6 +420,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 +493,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; @@ -579,26 +589,139 @@ inline std::string remove_annotations(std::string_view content, std::span module_patterns) { - auto [new_content, removed_classes] = remove_imports(content, parameters.patterns_, parameters.names_); + 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 (parameters.also_remove_annotations_) + if (pos != std::ssize(content)) { - 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) + ++pos; + new_content.clear(); + new_content.append(content, 0, pos); + while (pos != std::ssize(content)) { - strict_mode->any_annotation_removed_.store(true, std::memory_order_release); + 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(const Path_origin_entry& path, std::string_view content, const Parameters& parameters) +{ + if (path.filename() == "module-info.java") + { + return remove_jpms_requires(content, parameters.module_patterns_); + } + else + { + auto [new_content, removed_classes] = remove_imports(content, parameters.patterns_, parameters.names_); + + if (parameters.also_remove_annotations_) + { + 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); + } + } + + return new_content; + } +} + inline std::string handle_file(const Path_origin_entry& path, const Parameters& parameters) try { @@ -621,7 +744,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_) { @@ -706,14 +829,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 3775aaa..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,9 +203,18 @@ 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"; + std::cout << "jurand: strict mode: '-a' was specified but no annotation was removed" << "\n"; exit_code = 3; } } 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) << ")"; } 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; +}